<commit_before>#include "FFmpegDecoderVideo.hpp"

#include <osg/Notify>

#include <stdexcept>
#include <string.h>

namespace osgFFmpeg {

FFmpegDecoderVideo::FFmpegDecoderVideo(PacketQueue & packets, FFmpegClocks & clocks) :
    m_packets(packets),
    m_clocks(clocks),
    m_stream(0),
    m_context(0),
    m_codec(0),
    m_packet_data(0),
    m_bytes_remaining(0),
    m_packet_pts(AV_NOPTS_VALUE),
    m_user_data(0),
    m_publish_func(0),
    m_exit(false)
{

}

FFmpegDecoderVideo::~FFmpegDecoderVideo()
{
    if (isRunning())
    {
        m_exit = true;
        join();
    }
}

void FFmpegDecoderVideo::open(AVStream * const stream)
{
    m_stream = stream;
    m_context = stream->codec;

    // Trust the video size given at this point
    // (avcodec_open seems to sometimes return a 0x0 size)
    m_width = m_context->width;
    m_height = m_context->height;
    findAspectRatio();

    // Find out whether we support Alpha channel
    m_alpha_channel = (m_context->pix_fmt == PIX_FMT_YUVA420P);

    // Find out the framerate
    m_frame_rate = av_q2d(stream->r_frame_rate);

    // Find the decoder for the video stream
    m_codec = avcodec_find_decoder(m_context->codec_id);

    if (m_codec == 0)
        throw std::runtime_error("avcodec_find_decoder() failed");

    // Inform the codec that we can handle truncated bitstreams
    //if (p_codec->capabilities & CODEC_CAP_TRUNCATED)
    //    m_context->flags |= CODEC_FLAG_TRUNCATED;

    // Open codec
    if (avcodec_open(m_context, m_codec) < 0)
        throw std::runtime_error("avcodec_open() failed");

    // Allocate video frame
    m_frame.reset(avcodec_alloc_frame());

    // Allocate converted RGB frame
    m_frame_rgba.reset(avcodec_alloc_frame());
    m_buffer_rgba.resize(avpicture_get_size(PIX_FMT_RGB32, width(), height()));
    m_buffer_rgba_public.resize(m_buffer_rgba.size());

    // Assign appropriate parts of the buffer to image planes in m_frame_rgba
    avpicture_fill((AVPicture *) m_frame_rgba.get(), &m_buffer_rgba[0], PIX_FMT_RGB32, width(), height());

    // Override get_buffer()/release_buffer() from codec context in order to retrieve the PTS of each frame.
    m_context->opaque = this;
    m_context->get_buffer = getBuffer;
    m_context->release_buffer = releaseBuffer;
}

void FFmpegDecoderVideo::run()
{
    try
    {
        decodeLoop();
    }

    catch (const std::exception & error)
    {
        osg::notify(osg::WARN) << "FFmpegDecoderVideo::run : " << error.what() << std::endl;
    }

    catch (...)
    {
        osg::notify(osg::WARN) << "FFmpegDecoderVideo::run : unhandled exception" << std::endl;
    }
}

void FFmpegDecoderVideo::decodeLoop()
{
    FFmpegPacket packet;
    double pts;

    while (! m_exit)
    {
        // Work on the current packet until we have decoded all of it

        while (m_bytes_remaining > 0)
        {
            // Save global PTS to be stored in m_frame via getBuffer()

            m_packet_pts = packet.packet.pts;

            // Decode video frame

            int frame_finished = 0;

            const int bytes_decoded = avcodec_decode_video(m_context, m_frame.get(), &frame_finished, m_packet_data, m_bytes_remaining);

            if (bytes_decoded < 0)
                throw std::runtime_error("avcodec_decode_video failed()");

            m_bytes_remaining -= bytes_decoded;
            m_packet_data += bytes_decoded;

            // Find out the frame pts

            if (packet.packet.dts == AV_NOPTS_VALUE && m_frame->opaque != 0 && *reinterpret_cast<const int64_t*>(m_frame->opaque) != AV_NOPTS_VALUE)
            {
                pts = *reinterpret_cast<const int64_t*>(m_frame->opaque);
            }
            else if (packet.packet.dts != AV_NOPTS_VALUE)
            {
                pts = packet.packet.dts;
            }
            else
            {
                pts = 0;
            }

            pts *= av_q2d(m_stream->time_base);

            // Publish the frame if we have decoded a complete frame
            if (frame_finished)
            {
                const double synched_pts = m_clocks.videoSynchClock(m_frame.get(), av_q2d(m_stream->time_base), pts);
                const double frame_delay = m_clocks.videoRefreshSchedule(synched_pts);

                publishFrame(frame_delay);
            }
        }

        // Get the next packet

        pts = 0;

        if (packet.valid())
            packet.clear();

        bool is_empty = true;
        packet = m_packets.timedPop(is_empty, 10);

        if (! is_empty)
        {
            if (packet.type == FFmpegPacket::PACKET_DATA)
            {
                m_bytes_remaining = packet.packet.size;
                m_packet_data = packet.packet.data;
            }
            else if (packet.type == FFmpegPacket::PACKET_FLUSH)
            {
                avcodec_flush_buffers(m_context);
                m_clocks.rewindVideo();
            }
        }
    }
}

void FFmpegDecoderVideo::findAspectRatio()
{
    double ratio = 0.0;

    if (m_context->sample_aspect_ratio.num != 0)
        ratio = (av_q2d(m_context->sample_aspect_ratio) * m_width) / m_height;

    if (ratio <= 0.0)
        ratio = double(m_width) / double(m_height);

    m_aspect_ratio = ratio;
}

void FFmpegDecoderVideo::publishFrame(const double delay)
{
    // If no publishing function, just ignore the frame
    if (m_publish_func == 0)
        return;

    // If the display delay is too small, we better skip the frame.
    if (delay < -0.010)
        return;

    const AVPicture * const src = (const AVPicture *) m_frame.get();
    AVPicture * const dst = (AVPicture *) m_frame_rgba.get();

    // Convert YUVA420p (i.e. YUV420p plus alpha channel) using our own routine

    if (m_context->pix_fmt == PIX_FMT_YUVA420P)
        yuva420pToRgba(dst, src, width(), height());
    else
        img_convert(dst, PIX_FMT_RGB32, src, m_context->pix_fmt, width(), height());

    // Flip and swap buffer
    swapBuffers();

    // Wait 'delay' seconds before publishing the picture.
    int i_delay = static_cast<int>(delay * 1000000 + 0.5);

    while (i_delay > 1000)
    {
        // Avoid infinite/very long loops
        if (m_exit)
            return;

        const int micro_delay = (std::min)(1000000, i_delay);

        OpenThreads::Thread::microSleep(micro_delay);

        i_delay -= micro_delay;
    }

    m_publish_func(* this, m_user_data);
}

void FFmpegDecoderVideo::swapBuffers()
{
    for (int h = 0; h < height(); ++h)
        memcpy(&m_buffer_rgba_public[(height() - h - 1) * width() * 4], &m_buffer_rgba[h * width() * 4], width() * 4);
}

void FFmpegDecoderVideo::yuva420pToRgba(AVPicture * const dst, const AVPicture * const src, int width, int height)
{
    img_convert(dst, PIX_FMT_RGB32, src, m_context->pix_fmt, width, height);

    const size_t bpp = 4;

    uint8_t * a_dst = dst->data[0] + 3;

    for (int h = 0; h < height; ++h) {

        const uint8_t * a_src = src->data[3] + h * src->linesize[3];

        for (int w = 0; w < width; ++w) {
            *a_dst = *a_src;
            a_dst += bpp;
            a_src += 1;
        }
    }
}

int FFmpegDecoderVideo::getBuffer(AVCodecContext * const context, AVFrame * const picture)
{
    const FFmpegDecoderVideo * const this_ = reinterpret_cast<const FFmpegDecoderVideo*>(context->opaque);

    const int result = avcodec_default_get_buffer(context, picture);
    int64_t * p_pts = reinterpret_cast<int64_t*>( av_malloc(sizeof(int64_t)) );

    *p_pts = this_->m_packet_pts;
    picture->opaque = p_pts;

    return result;
}

void FFmpegDecoderVideo::releaseBuffer(AVCodecContext * const context, AVFrame * const picture)
{
    if (picture != 0)
        av_freep(&picture->opaque);

    avcodec_default_release_buffer(context, picture);
}

} // namespace osgFFmpeg
<commit_msg>Added extern for img_convert to get round disappeance of the declaration from headers.<commit_after>#include "FFmpegDecoderVideo.hpp"

#include <osg/Notify>

#include <stdexcept>
#include <string.h>

extern "C"
{
    int img_convert(AVPicture *dst, int dst_pix_fmt, const AVPicture *src,
                int src_pix_fmt, int src_width, int src_height);

};

namespace osgFFmpeg {

FFmpegDecoderVideo::FFmpegDecoderVideo(PacketQueue & packets, FFmpegClocks & clocks) :
    m_packets(packets),
    m_clocks(clocks),
    m_stream(0),
    m_context(0),
    m_codec(0),
    m_packet_data(0),
    m_bytes_remaining(0),
    m_packet_pts(AV_NOPTS_VALUE),
    m_user_data(0),
    m_publish_func(0),
    m_exit(false)
{

}

FFmpegDecoderVideo::~FFmpegDecoderVideo()
{
    if (isRunning())
    {
        m_exit = true;
        join();
    }
}

void FFmpegDecoderVideo::open(AVStream * const stream)
{
    m_stream = stream;
    m_context = stream->codec;

    // Trust the video size given at this point
    // (avcodec_open seems to sometimes return a 0x0 size)
    m_width = m_context->width;
    m_height = m_context->height;
    findAspectRatio();

    // Find out whether we support Alpha channel
    m_alpha_channel = (m_context->pix_fmt == PIX_FMT_YUVA420P);

    // Find out the framerate
    m_frame_rate = av_q2d(stream->r_frame_rate);

    // Find the decoder for the video stream
    m_codec = avcodec_find_decoder(m_context->codec_id);

    if (m_codec == 0)
        throw std::runtime_error("avcodec_find_decoder() failed");

    // Inform the codec that we can handle truncated bitstreams
    //if (p_codec->capabilities & CODEC_CAP_TRUNCATED)
    //    m_context->flags |= CODEC_FLAG_TRUNCATED;

    // Open codec
    if (avcodec_open(m_context, m_codec) < 0)
        throw std::runtime_error("avcodec_open() failed");

    // Allocate video frame
    m_frame.reset(avcodec_alloc_frame());

    // Allocate converted RGB frame
    m_frame_rgba.reset(avcodec_alloc_frame());
    m_buffer_rgba.resize(avpicture_get_size(PIX_FMT_RGB32, width(), height()));
    m_buffer_rgba_public.resize(m_buffer_rgba.size());

    // Assign appropriate parts of the buffer to image planes in m_frame_rgba
    avpicture_fill((AVPicture *) m_frame_rgba.get(), &m_buffer_rgba[0], PIX_FMT_RGB32, width(), height());

    // Override get_buffer()/release_buffer() from codec context in order to retrieve the PTS of each frame.
    m_context->opaque = this;
    m_context->get_buffer = getBuffer;
    m_context->release_buffer = releaseBuffer;
}

void FFmpegDecoderVideo::run()
{
    try
    {
        decodeLoop();
    }

    catch (const std::exception & error)
    {
        osg::notify(osg::WARN) << "FFmpegDecoderVideo::run : " << error.what() << std::endl;
    }

    catch (...)
    {
        osg::notify(osg::WARN) << "FFmpegDecoderVideo::run : unhandled exception" << std::endl;
    }
}

void FFmpegDecoderVideo::decodeLoop()
{
    FFmpegPacket packet;
    double pts;

    while (! m_exit)
    {
        // Work on the current packet until we have decoded all of it

        while (m_bytes_remaining > 0)
        {
            // Save global PTS to be stored in m_frame via getBuffer()

            m_packet_pts = packet.packet.pts;

            // Decode video frame

            int frame_finished = 0;

            const int bytes_decoded = avcodec_decode_video(m_context, m_frame.get(), &frame_finished, m_packet_data, m_bytes_remaining);

            if (bytes_decoded < 0)
                throw std::runtime_error("avcodec_decode_video failed()");

            m_bytes_remaining -= bytes_decoded;
            m_packet_data += bytes_decoded;

            // Find out the frame pts

            if (packet.packet.dts == AV_NOPTS_VALUE && m_frame->opaque != 0 && *reinterpret_cast<const int64_t*>(m_frame->opaque) != AV_NOPTS_VALUE)
            {
                pts = *reinterpret_cast<const int64_t*>(m_frame->opaque);
            }
            else if (packet.packet.dts != AV_NOPTS_VALUE)
            {
                pts = packet.packet.dts;
            }
            else
            {
                pts = 0;
            }

            pts *= av_q2d(m_stream->time_base);

            // Publish the frame if we have decoded a complete frame
            if (frame_finished)
            {
                const double synched_pts = m_clocks.videoSynchClock(m_frame.get(), av_q2d(m_stream->time_base), pts);
                const double frame_delay = m_clocks.videoRefreshSchedule(synched_pts);

                publishFrame(frame_delay);
            }
        }

        // Get the next packet

        pts = 0;

        if (packet.valid())
            packet.clear();

        bool is_empty = true;
        packet = m_packets.timedPop(is_empty, 10);

        if (! is_empty)
        {
            if (packet.type == FFmpegPacket::PACKET_DATA)
            {
                m_bytes_remaining = packet.packet.size;
                m_packet_data = packet.packet.data;
            }
            else if (packet.type == FFmpegPacket::PACKET_FLUSH)
            {
                avcodec_flush_buffers(m_context);
                m_clocks.rewindVideo();
            }
        }
    }
}

void FFmpegDecoderVideo::findAspectRatio()
{
    double ratio = 0.0;

    if (m_context->sample_aspect_ratio.num != 0)
        ratio = (av_q2d(m_context->sample_aspect_ratio) * m_width) / m_height;

    if (ratio <= 0.0)
        ratio = double(m_width) / double(m_height);

    m_aspect_ratio = ratio;
}

void FFmpegDecoderVideo::publishFrame(const double delay)
{
    // If no publishing function, just ignore the frame
    if (m_publish_func == 0)
        return;

    // If the display delay is too small, we better skip the frame.
    if (delay < -0.010)
        return;

    const AVPicture * const src = (const AVPicture *) m_frame.get();
    AVPicture * const dst = (AVPicture *) m_frame_rgba.get();

    // Convert YUVA420p (i.e. YUV420p plus alpha channel) using our own routine

    if (m_context->pix_fmt == PIX_FMT_YUVA420P)
        yuva420pToRgba(dst, src, width(), height());
    else
        img_convert(dst, PIX_FMT_RGB32, src, m_context->pix_fmt, width(), height());

    // Flip and swap buffer
    swapBuffers();

    // Wait 'delay' seconds before publishing the picture.
    int i_delay = static_cast<int>(delay * 1000000 + 0.5);

    while (i_delay > 1000)
    {
        // Avoid infinite/very long loops
        if (m_exit)
            return;

        const int micro_delay = (std::min)(1000000, i_delay);

        OpenThreads::Thread::microSleep(micro_delay);

        i_delay -= micro_delay;
    }

    m_publish_func(* this, m_user_data);
}

void FFmpegDecoderVideo::swapBuffers()
{
    for (int h = 0; h < height(); ++h)
        memcpy(&m_buffer_rgba_public[(height() - h - 1) * width() * 4], &m_buffer_rgba[h * width() * 4], width() * 4);
}

void FFmpegDecoderVideo::yuva420pToRgba(AVPicture * const dst, const AVPicture * const src, int width, int height)
{
    img_convert(dst, PIX_FMT_RGB32, src, m_context->pix_fmt, width, height);

    const size_t bpp = 4;

    uint8_t * a_dst = dst->data[0] + 3;

    for (int h = 0; h < height; ++h) {

        const uint8_t * a_src = src->data[3] + h * src->linesize[3];

        for (int w = 0; w < width; ++w) {
            *a_dst = *a_src;
            a_dst += bpp;
            a_src += 1;
        }
    }
}

int FFmpegDecoderVideo::getBuffer(AVCodecContext * const context, AVFrame * const picture)
{
    const FFmpegDecoderVideo * const this_ = reinterpret_cast<const FFmpegDecoderVideo*>(context->opaque);

    const int result = avcodec_default_get_buffer(context, picture);
    int64_t * p_pts = reinterpret_cast<int64_t*>( av_malloc(sizeof(int64_t)) );

    *p_pts = this_->m_packet_pts;
    picture->opaque = p_pts;

    return result;
}

void FFmpegDecoderVideo::releaseBuffer(AVCodecContext * const context, AVFrame * const picture)
{
    if (picture != 0)
        av_freep(&picture->opaque);

    avcodec_default_release_buffer(context, picture);
}

} // namespace osgFFmpeg
<|endoftext|>


<commit_before>//===-- MachODump.cpp - Object file dumping utility for llvm --------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the MachO-specific dumper for llvm-readobj.
//
//===----------------------------------------------------------------------===//

#include "llvm-readobj.h"
#include "Error.h"
#include "ObjDumper.h"
#include "StreamWriter.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Object/MachO.h"
#include "llvm/Support/Casting.h"

using namespace llvm;
using namespace object;

namespace {

class MachODumper : public ObjDumper {
public:
  MachODumper(const MachOObjectFile *Obj, StreamWriter& Writer)
    : ObjDumper(Writer)
    , Obj(Obj) { }

  virtual void printFileHeaders() override;
  virtual void printSections() override;
  virtual void printRelocations() override;
  virtual void printSymbols() override;
  virtual void printDynamicSymbols() override;
  virtual void printUnwindInfo() override;

private:
  void printSymbol(symbol_iterator SymI);

  void printRelocation(section_iterator SecI, relocation_iterator RelI);

  void printRelocation(const MachOObjectFile *Obj,
                       section_iterator SecI, relocation_iterator RelI);

  void printSections(const MachOObjectFile *Obj);

  const MachOObjectFile *Obj;
};

} // namespace

namespace llvm {

error_code createMachODumper(const object::ObjectFile *Obj,
                             StreamWriter &Writer,
                             std::unique_ptr<ObjDumper> &Result) {
  const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj);
  if (!MachOObj)
    return readobj_error::unsupported_obj_file_format;

  Result.reset(new MachODumper(MachOObj, Writer));
  return readobj_error::success;
}

} // namespace llvm

static const EnumEntry<unsigned> MachOSectionTypes[] = {
  { "Regular"                        , 0x00 },
  { "ZeroFill"                       , 0x01 },
  { "CStringLiterals"                , 0x02 },
  { "4ByteLiterals"                  , 0x03 },
  { "8ByteLiterals"                  , 0x04 },
  { "LiteralPointers"                , 0x05 },
  { "NonLazySymbolPointers"          , 0x06 },
  { "LazySymbolPointers"             , 0x07 },
  { "SymbolStubs"                    , 0x08 },
  { "ModInitFuncs"                   , 0x09 },
  { "ModTermFuncs"                   , 0x0A },
  { "Coalesced"                      , 0x0B },
  { "GBZeroFill"                     , 0x0C },
  { "Interposing"                    , 0x0D },
  { "16ByteLiterals"                 , 0x0E },
  { "DTraceDOF"                      , 0x0F },
  { "LazyDylibSymbolPoints"          , 0x10 },
  { "ThreadLocalRegular"             , 0x11 },
  { "ThreadLocalZerofill"            , 0x12 },
  { "ThreadLocalVariables"           , 0x13 },
  { "ThreadLocalVariablePointers"    , 0x14 },
  { "ThreadLocalInitFunctionPointers", 0x15 }
};

static const EnumEntry<unsigned> MachOSectionAttributes[] = {
  { "LocReloc"         , 1 <<  0 /*S_ATTR_LOC_RELOC          */ },
  { "ExtReloc"         , 1 <<  1 /*S_ATTR_EXT_RELOC          */ },
  { "SomeInstructions" , 1 <<  2 /*S_ATTR_SOME_INSTRUCTIONS  */ },
  { "Debug"            , 1 << 17 /*S_ATTR_DEBUG              */ },
  { "SelfModifyingCode", 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/ },
  { "LiveSupport"      , 1 << 19 /*S_ATTR_LIVE_SUPPORT       */ },
  { "NoDeadStrip"      , 1 << 20 /*S_ATTR_NO_DEAD_STRIP      */ },
  { "StripStaticSyms"  , 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS  */ },
  { "NoTOC"            , 1 << 22 /*S_ATTR_NO_TOC             */ },
  { "PureInstructions" , 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS  */ },
};

static const EnumEntry<unsigned> MachOSymbolRefTypes[] = {
  { "UndefinedNonLazy",                     0 },
  { "ReferenceFlagUndefinedLazy",           1 },
  { "ReferenceFlagDefined",                 2 },
  { "ReferenceFlagPrivateDefined",          3 },
  { "ReferenceFlagPrivateUndefinedNonLazy", 4 },
  { "ReferenceFlagPrivateUndefinedLazy",    5 }
};

static const EnumEntry<unsigned> MachOSymbolFlags[] = {
  { "ReferencedDynamically", 0x10 },
  { "NoDeadStrip",           0x20 },
  { "WeakRef",               0x40 },
  { "WeakDef",               0x80 }
};

static const EnumEntry<unsigned> MachOSymbolTypes[] = {
  { "Undef",           0x0 },
  { "Abs",             0x2 },
  { "Indirect",        0xA },
  { "PreboundUndef",   0xC },
  { "Section",         0xE }
};

namespace {
  struct MachOSection {
    ArrayRef<char> Name;
    ArrayRef<char> SegmentName;
    uint64_t Address;
    uint64_t Size;
    uint32_t Offset;
    uint32_t Alignment;
    uint32_t RelocationTableOffset;
    uint32_t NumRelocationTableEntries;
    uint32_t Flags;
    uint32_t Reserved1;
    uint32_t Reserved2;
  };

  struct MachOSymbol {
    uint32_t StringIndex;
    uint8_t Type;
    uint8_t SectionIndex;
    uint16_t Flags;
    uint64_t Value;
  };
}

static void getSection(const MachOObjectFile *Obj,
                       DataRefImpl Sec,
                       MachOSection &Section) {
  if (!Obj->is64Bit()) {
    MachO::section Sect = Obj->getSection(Sec);
    Section.Address     = Sect.addr;
    Section.Size        = Sect.size;
    Section.Offset      = Sect.offset;
    Section.Alignment   = Sect.align;
    Section.RelocationTableOffset = Sect.reloff;
    Section.NumRelocationTableEntries = Sect.nreloc;
    Section.Flags       = Sect.flags;
    Section.Reserved1   = Sect.reserved1;
    Section.Reserved2   = Sect.reserved2;
    return;
  }
  MachO::section_64 Sect = Obj->getSection64(Sec);
  Section.Address     = Sect.addr;
  Section.Size        = Sect.size;
  Section.Offset      = Sect.offset;
  Section.Alignment   = Sect.align;
  Section.RelocationTableOffset = Sect.reloff;
  Section.NumRelocationTableEntries = Sect.nreloc;
  Section.Flags       = Sect.flags;
  Section.Reserved1   = Sect.reserved1;
  Section.Reserved2   = Sect.reserved2;
}

static void getSymbol(const MachOObjectFile *Obj,
                      DataRefImpl DRI,
                      MachOSymbol &Symbol) {
  if (!Obj->is64Bit()) {
    MachO::nlist Entry = Obj->getSymbolTableEntry(DRI);
    Symbol.StringIndex  = Entry.n_strx;
    Symbol.Type         = Entry.n_type;
    Symbol.SectionIndex = Entry.n_sect;
    Symbol.Flags        = Entry.n_desc;
    Symbol.Value        = Entry.n_value;
    return;
  }
  MachO::nlist_64 Entry = Obj->getSymbol64TableEntry(DRI);
  Symbol.StringIndex  = Entry.n_strx;
  Symbol.Type         = Entry.n_type;
  Symbol.SectionIndex = Entry.n_sect;
  Symbol.Flags        = Entry.n_desc;
  Symbol.Value        = Entry.n_value;
}

void MachODumper::printFileHeaders() {
  W.startLine() << "FileHeaders not implemented.\n";
}

void MachODumper::printSections() {
  return printSections(Obj);
}

void MachODumper::printSections(const MachOObjectFile *Obj) {
  ListScope Group(W, "Sections");

  int SectionIndex = -1;
  for (section_iterator SecI = Obj->section_begin(),
                        SecE = Obj->section_end();
       SecI != SecE; ++SecI) {
    ++SectionIndex;

    MachOSection Section;
    getSection(Obj, SecI->getRawDataRefImpl(), Section);
    DataRefImpl DR = SecI->getRawDataRefImpl();

    StringRef Name;
    if (error(SecI->getName(Name)))
        Name = "";

    ArrayRef<char> RawName = Obj->getSectionRawName(DR);
    StringRef SegmentName = Obj->getSectionFinalSegmentName(DR);
    ArrayRef<char> RawSegmentName = Obj->getSectionRawFinalSegmentName(DR);

    DictScope SectionD(W, "Section");
    W.printNumber("Index", SectionIndex);
    W.printBinary("Name", Name, RawName);
    W.printBinary("Segment", SegmentName, RawSegmentName);
    W.printHex   ("Address", Section.Address);
    W.printHex   ("Size", Section.Size);
    W.printNumber("Offset", Section.Offset);
    W.printNumber("Alignment", Section.Alignment);
    W.printHex   ("RelocationOffset", Section.RelocationTableOffset);
    W.printNumber("RelocationCount", Section.NumRelocationTableEntries);
    W.printEnum  ("Type", Section.Flags & 0xFF,
                  makeArrayRef(MachOSectionAttributes));
    W.printFlags ("Attributes", Section.Flags >> 8,
                  makeArrayRef(MachOSectionAttributes));
    W.printHex   ("Reserved1", Section.Reserved1);
    W.printHex   ("Reserved2", Section.Reserved2);

    if (opts::SectionRelocations) {
      ListScope D(W, "Relocations");
      for (relocation_iterator RelI = SecI->relocation_begin(),
                               RelE = SecI->relocation_end();
           RelI != RelE; ++RelI)
        printRelocation(SecI, RelI);
    }

    if (opts::SectionSymbols) {
      ListScope D(W, "Symbols");
      for (symbol_iterator SymI = Obj->symbol_begin(),
                           SymE = Obj->symbol_end();
           SymI != SymE; ++SymI) {
        bool Contained = false;
        if (SecI->containsSymbol(*SymI, Contained) || !Contained)
          continue;

        printSymbol(SymI);
      }
    }

    if (opts::SectionData) {
      StringRef Data;
      if (error(SecI->getContents(Data))) break;

      W.printBinaryBlock("SectionData", Data);
    }
  }
}

void MachODumper::printRelocations() {
  ListScope D(W, "Relocations");

  error_code EC;
  for (section_iterator SecI = Obj->section_begin(),
                        SecE = Obj->section_end();
       SecI != SecE; ++SecI) {
    StringRef Name;
    if (error(SecI->getName(Name)))
      continue;

    bool PrintedGroup = false;
    for (relocation_iterator RelI = SecI->relocation_begin(),
                             RelE = SecI->relocation_end();
         RelI != RelE; ++RelI) {
      if (!PrintedGroup) {
        W.startLine() << "Section " << Name << " {\n";
        W.indent();
        PrintedGroup = true;
      }

      printRelocation(SecI, RelI);
    }

    if (PrintedGroup) {
      W.unindent();
      W.startLine() << "}\n";
    }
  }
}

void MachODumper::printRelocation(section_iterator SecI,
                                  relocation_iterator RelI) {
  return printRelocation(Obj, SecI, RelI);
}

void MachODumper::printRelocation(const MachOObjectFile *Obj,
                                  section_iterator SecI,
                                  relocation_iterator RelI) {
  uint64_t Offset;
  SmallString<32> RelocName;
  StringRef SymbolName;
  if (error(RelI->getOffset(Offset))) return;
  if (error(RelI->getTypeName(RelocName))) return;
  symbol_iterator Symbol = RelI->getSymbol();
  if (Symbol != Obj->symbol_end() &&
      error(Symbol->getName(SymbolName)))
    return;

  DataRefImpl DR = RelI->getRawDataRefImpl();
  MachO::any_relocation_info RE = Obj->getRelocation(DR);
  bool IsScattered = Obj->isRelocationScattered(RE);

  if (opts::ExpandRelocs) {
    DictScope Group(W, "Relocation");
    W.printHex("Offset", Offset);
    W.printNumber("PCRel", Obj->getAnyRelocationPCRel(RE));
    W.printNumber("Length", Obj->getAnyRelocationLength(RE));
    if (IsScattered)
      W.printString("Extern", StringRef("N/A"));
    else
      W.printNumber("Extern", Obj->getPlainRelocationExternal(RE));
    W.printNumber("Type", RelocName, Obj->getAnyRelocationType(RE));
    W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-");
    W.printNumber("Scattered", IsScattered);
  } else {
    raw_ostream& OS = W.startLine();
    OS << W.hex(Offset)
       << " " << Obj->getAnyRelocationPCRel(RE)
       << " " << Obj->getAnyRelocationLength(RE);
    if (IsScattered)
      OS << " n/a";
    else
      OS << " " << Obj->getPlainRelocationExternal(RE);
    OS << " " << RelocName
       << " " << IsScattered
       << " " << (SymbolName.size() > 0 ? SymbolName : "-")
       << "\n";
  }
}

void MachODumper::printSymbols() {
  ListScope Group(W, "Symbols");

  for (symbol_iterator SymI = Obj->symbol_begin(), SymE = Obj->symbol_end();
       SymI != SymE; ++SymI) {
    printSymbol(SymI);
  }
}

void MachODumper::printDynamicSymbols() {
  ListScope Group(W, "DynamicSymbols");
}

void MachODumper::printSymbol(symbol_iterator SymI) {
  StringRef SymbolName;
  if (SymI->getName(SymbolName))
    SymbolName = "";

  MachOSymbol Symbol;
  getSymbol(Obj, SymI->getRawDataRefImpl(), Symbol);

  StringRef SectionName = "";
  section_iterator SecI(Obj->section_begin());
  if (!error(SymI->getSection(SecI)) &&
      SecI != Obj->section_end())
      error(SecI->getName(SectionName));

  DictScope D(W, "Symbol");
  W.printNumber("Name", SymbolName, Symbol.StringIndex);
  if (Symbol.Type & MachO::N_STAB) {
    W.printHex ("Type", "SymDebugTable", Symbol.Type);
  } else {
    if (Symbol.Type & MachO::N_PEXT)
      W.startLine() << "PrivateExtern\n";
    if (Symbol.Type & MachO::N_EXT)
      W.startLine() << "Extern\n";
    W.printEnum("Type", Symbol.Type & MachO::N_TYPE,
                makeArrayRef(MachOSymbolTypes));
  }
  W.printHex   ("Section", SectionName, Symbol.SectionIndex);
  W.printEnum  ("RefType", static_cast<uint16_t>(Symbol.Flags & 0xF),
                  makeArrayRef(MachOSymbolRefTypes));
  W.printFlags ("Flags", static_cast<uint16_t>(Symbol.Flags & ~0xF),
                  makeArrayRef(MachOSymbolFlags));
  W.printHex   ("Value", Symbol.Value);
}

void MachODumper::printUnwindInfo() {
  W.startLine() << "UnwindInfo not implemented.\n";
}
<commit_msg>Fix warning about mismatched signs in comparison.<commit_after>//===-- MachODump.cpp - Object file dumping utility for llvm --------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the MachO-specific dumper for llvm-readobj.
//
//===----------------------------------------------------------------------===//

#include "llvm-readobj.h"
#include "Error.h"
#include "ObjDumper.h"
#include "StreamWriter.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Object/MachO.h"
#include "llvm/Support/Casting.h"

using namespace llvm;
using namespace object;

namespace {

class MachODumper : public ObjDumper {
public:
  MachODumper(const MachOObjectFile *Obj, StreamWriter& Writer)
    : ObjDumper(Writer)
    , Obj(Obj) { }

  virtual void printFileHeaders() override;
  virtual void printSections() override;
  virtual void printRelocations() override;
  virtual void printSymbols() override;
  virtual void printDynamicSymbols() override;
  virtual void printUnwindInfo() override;

private:
  void printSymbol(symbol_iterator SymI);

  void printRelocation(section_iterator SecI, relocation_iterator RelI);

  void printRelocation(const MachOObjectFile *Obj,
                       section_iterator SecI, relocation_iterator RelI);

  void printSections(const MachOObjectFile *Obj);

  const MachOObjectFile *Obj;
};

} // namespace

namespace llvm {

error_code createMachODumper(const object::ObjectFile *Obj,
                             StreamWriter &Writer,
                             std::unique_ptr<ObjDumper> &Result) {
  const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj);
  if (!MachOObj)
    return readobj_error::unsupported_obj_file_format;

  Result.reset(new MachODumper(MachOObj, Writer));
  return readobj_error::success;
}

} // namespace llvm

static const EnumEntry<unsigned> MachOSectionTypes[] = {
  { "Regular"                        , 0x00 },
  { "ZeroFill"                       , 0x01 },
  { "CStringLiterals"                , 0x02 },
  { "4ByteLiterals"                  , 0x03 },
  { "8ByteLiterals"                  , 0x04 },
  { "LiteralPointers"                , 0x05 },
  { "NonLazySymbolPointers"          , 0x06 },
  { "LazySymbolPointers"             , 0x07 },
  { "SymbolStubs"                    , 0x08 },
  { "ModInitFuncs"                   , 0x09 },
  { "ModTermFuncs"                   , 0x0A },
  { "Coalesced"                      , 0x0B },
  { "GBZeroFill"                     , 0x0C },
  { "Interposing"                    , 0x0D },
  { "16ByteLiterals"                 , 0x0E },
  { "DTraceDOF"                      , 0x0F },
  { "LazyDylibSymbolPoints"          , 0x10 },
  { "ThreadLocalRegular"             , 0x11 },
  { "ThreadLocalZerofill"            , 0x12 },
  { "ThreadLocalVariables"           , 0x13 },
  { "ThreadLocalVariablePointers"    , 0x14 },
  { "ThreadLocalInitFunctionPointers", 0x15 }
};

static const EnumEntry<unsigned> MachOSectionAttributes[] = {
  { "LocReloc"         , 1 <<  0 /*S_ATTR_LOC_RELOC          */ },
  { "ExtReloc"         , 1 <<  1 /*S_ATTR_EXT_RELOC          */ },
  { "SomeInstructions" , 1 <<  2 /*S_ATTR_SOME_INSTRUCTIONS  */ },
  { "Debug"            , 1 << 17 /*S_ATTR_DEBUG              */ },
  { "SelfModifyingCode", 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/ },
  { "LiveSupport"      , 1 << 19 /*S_ATTR_LIVE_SUPPORT       */ },
  { "NoDeadStrip"      , 1 << 20 /*S_ATTR_NO_DEAD_STRIP      */ },
  { "StripStaticSyms"  , 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS  */ },
  { "NoTOC"            , 1 << 22 /*S_ATTR_NO_TOC             */ },
  { "PureInstructions" , 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS  */ },
};

static const EnumEntry<unsigned> MachOSymbolRefTypes[] = {
  { "UndefinedNonLazy",                     0 },
  { "ReferenceFlagUndefinedLazy",           1 },
  { "ReferenceFlagDefined",                 2 },
  { "ReferenceFlagPrivateDefined",          3 },
  { "ReferenceFlagPrivateUndefinedNonLazy", 4 },
  { "ReferenceFlagPrivateUndefinedLazy",    5 }
};

static const EnumEntry<unsigned> MachOSymbolFlags[] = {
  { "ReferencedDynamically", 0x10 },
  { "NoDeadStrip",           0x20 },
  { "WeakRef",               0x40 },
  { "WeakDef",               0x80 }
};

static const EnumEntry<unsigned> MachOSymbolTypes[] = {
  { "Undef",           0x0 },
  { "Abs",             0x2 },
  { "Indirect",        0xA },
  { "PreboundUndef",   0xC },
  { "Section",         0xE }
};

namespace {
  struct MachOSection {
    ArrayRef<char> Name;
    ArrayRef<char> SegmentName;
    uint64_t Address;
    uint64_t Size;
    uint32_t Offset;
    uint32_t Alignment;
    uint32_t RelocationTableOffset;
    uint32_t NumRelocationTableEntries;
    uint32_t Flags;
    uint32_t Reserved1;
    uint32_t Reserved2;
  };

  struct MachOSymbol {
    uint32_t StringIndex;
    uint8_t Type;
    uint8_t SectionIndex;
    uint16_t Flags;
    uint64_t Value;
  };
}

static void getSection(const MachOObjectFile *Obj,
                       DataRefImpl Sec,
                       MachOSection &Section) {
  if (!Obj->is64Bit()) {
    MachO::section Sect = Obj->getSection(Sec);
    Section.Address     = Sect.addr;
    Section.Size        = Sect.size;
    Section.Offset      = Sect.offset;
    Section.Alignment   = Sect.align;
    Section.RelocationTableOffset = Sect.reloff;
    Section.NumRelocationTableEntries = Sect.nreloc;
    Section.Flags       = Sect.flags;
    Section.Reserved1   = Sect.reserved1;
    Section.Reserved2   = Sect.reserved2;
    return;
  }
  MachO::section_64 Sect = Obj->getSection64(Sec);
  Section.Address     = Sect.addr;
  Section.Size        = Sect.size;
  Section.Offset      = Sect.offset;
  Section.Alignment   = Sect.align;
  Section.RelocationTableOffset = Sect.reloff;
  Section.NumRelocationTableEntries = Sect.nreloc;
  Section.Flags       = Sect.flags;
  Section.Reserved1   = Sect.reserved1;
  Section.Reserved2   = Sect.reserved2;
}

static void getSymbol(const MachOObjectFile *Obj,
                      DataRefImpl DRI,
                      MachOSymbol &Symbol) {
  if (!Obj->is64Bit()) {
    MachO::nlist Entry = Obj->getSymbolTableEntry(DRI);
    Symbol.StringIndex  = Entry.n_strx;
    Symbol.Type         = Entry.n_type;
    Symbol.SectionIndex = Entry.n_sect;
    Symbol.Flags        = Entry.n_desc;
    Symbol.Value        = Entry.n_value;
    return;
  }
  MachO::nlist_64 Entry = Obj->getSymbol64TableEntry(DRI);
  Symbol.StringIndex  = Entry.n_strx;
  Symbol.Type         = Entry.n_type;
  Symbol.SectionIndex = Entry.n_sect;
  Symbol.Flags        = Entry.n_desc;
  Symbol.Value        = Entry.n_value;
}

void MachODumper::printFileHeaders() {
  W.startLine() << "FileHeaders not implemented.\n";
}

void MachODumper::printSections() {
  return printSections(Obj);
}

void MachODumper::printSections(const MachOObjectFile *Obj) {
  ListScope Group(W, "Sections");

  int SectionIndex = -1;
  for (section_iterator SecI = Obj->section_begin(),
                        SecE = Obj->section_end();
       SecI != SecE; ++SecI) {
    ++SectionIndex;

    MachOSection Section;
    getSection(Obj, SecI->getRawDataRefImpl(), Section);
    DataRefImpl DR = SecI->getRawDataRefImpl();

    StringRef Name;
    if (error(SecI->getName(Name)))
        Name = "";

    ArrayRef<char> RawName = Obj->getSectionRawName(DR);
    StringRef SegmentName = Obj->getSectionFinalSegmentName(DR);
    ArrayRef<char> RawSegmentName = Obj->getSectionRawFinalSegmentName(DR);

    DictScope SectionD(W, "Section");
    W.printNumber("Index", SectionIndex);
    W.printBinary("Name", Name, RawName);
    W.printBinary("Segment", SegmentName, RawSegmentName);
    W.printHex   ("Address", Section.Address);
    W.printHex   ("Size", Section.Size);
    W.printNumber("Offset", Section.Offset);
    W.printNumber("Alignment", Section.Alignment);
    W.printHex   ("RelocationOffset", Section.RelocationTableOffset);
    W.printNumber("RelocationCount", Section.NumRelocationTableEntries);
    W.printEnum  ("Type", Section.Flags & 0xFF,
                  makeArrayRef(MachOSectionAttributes));
    W.printFlags ("Attributes", Section.Flags >> 8,
                  makeArrayRef(MachOSectionAttributes));
    W.printHex   ("Reserved1", Section.Reserved1);
    W.printHex   ("Reserved2", Section.Reserved2);

    if (opts::SectionRelocations) {
      ListScope D(W, "Relocations");
      for (relocation_iterator RelI = SecI->relocation_begin(),
                               RelE = SecI->relocation_end();
           RelI != RelE; ++RelI)
        printRelocation(SecI, RelI);
    }

    if (opts::SectionSymbols) {
      ListScope D(W, "Symbols");
      for (symbol_iterator SymI = Obj->symbol_begin(),
                           SymE = Obj->symbol_end();
           SymI != SymE; ++SymI) {
        bool Contained = false;
        if (SecI->containsSymbol(*SymI, Contained) || !Contained)
          continue;

        printSymbol(SymI);
      }
    }

    if (opts::SectionData) {
      StringRef Data;
      if (error(SecI->getContents(Data))) break;

      W.printBinaryBlock("SectionData", Data);
    }
  }
}

void MachODumper::printRelocations() {
  ListScope D(W, "Relocations");

  error_code EC;
  for (section_iterator SecI = Obj->section_begin(),
                        SecE = Obj->section_end();
       SecI != SecE; ++SecI) {
    StringRef Name;
    if (error(SecI->getName(Name)))
      continue;

    bool PrintedGroup = false;
    for (relocation_iterator RelI = SecI->relocation_begin(),
                             RelE = SecI->relocation_end();
         RelI != RelE; ++RelI) {
      if (!PrintedGroup) {
        W.startLine() << "Section " << Name << " {\n";
        W.indent();
        PrintedGroup = true;
      }

      printRelocation(SecI, RelI);
    }

    if (PrintedGroup) {
      W.unindent();
      W.startLine() << "}\n";
    }
  }
}

void MachODumper::printRelocation(section_iterator SecI,
                                  relocation_iterator RelI) {
  return printRelocation(Obj, SecI, RelI);
}

void MachODumper::printRelocation(const MachOObjectFile *Obj,
                                  section_iterator SecI,
                                  relocation_iterator RelI) {
  uint64_t Offset;
  SmallString<32> RelocName;
  StringRef SymbolName;
  if (error(RelI->getOffset(Offset))) return;
  if (error(RelI->getTypeName(RelocName))) return;
  symbol_iterator Symbol = RelI->getSymbol();
  if (Symbol != Obj->symbol_end() &&
      error(Symbol->getName(SymbolName)))
    return;

  DataRefImpl DR = RelI->getRawDataRefImpl();
  MachO::any_relocation_info RE = Obj->getRelocation(DR);
  bool IsScattered = Obj->isRelocationScattered(RE);

  if (opts::ExpandRelocs) {
    DictScope Group(W, "Relocation");
    W.printHex("Offset", Offset);
    W.printNumber("PCRel", Obj->getAnyRelocationPCRel(RE));
    W.printNumber("Length", Obj->getAnyRelocationLength(RE));
    if (IsScattered)
      W.printString("Extern", StringRef("N/A"));
    else
      W.printNumber("Extern", Obj->getPlainRelocationExternal(RE));
    W.printNumber("Type", RelocName, Obj->getAnyRelocationType(RE));
    W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-");
    W.printNumber("Scattered", IsScattered);
  } else {
    raw_ostream& OS = W.startLine();
    OS << W.hex(Offset)
       << " " << Obj->getAnyRelocationPCRel(RE)
       << " " << Obj->getAnyRelocationLength(RE);
    if (IsScattered)
      OS << " n/a";
    else
      OS << " " << Obj->getPlainRelocationExternal(RE);
    OS << " " << RelocName
       << " " << IsScattered
       << " " << (SymbolName.size() > 0 ? SymbolName : "-")
       << "\n";
  }
}

void MachODumper::printSymbols() {
  ListScope Group(W, "Symbols");

  for (symbol_iterator SymI = Obj->symbol_begin(), SymE = Obj->symbol_end();
       SymI != SymE; ++SymI) {
    printSymbol(SymI);
  }
}

void MachODumper::printDynamicSymbols() {
  ListScope Group(W, "DynamicSymbols");
}

void MachODumper::printSymbol(symbol_iterator SymI) {
  StringRef SymbolName;
  if (SymI->getName(SymbolName))
    SymbolName = "";

  MachOSymbol Symbol;
  getSymbol(Obj, SymI->getRawDataRefImpl(), Symbol);

  StringRef SectionName = "";
  section_iterator SecI(Obj->section_begin());
  if (!error(SymI->getSection(SecI)) &&
      SecI != Obj->section_end())
      error(SecI->getName(SectionName));

  DictScope D(W, "Symbol");
  W.printNumber("Name", SymbolName, Symbol.StringIndex);
  if (Symbol.Type & MachO::N_STAB) {
    W.printHex ("Type", "SymDebugTable", Symbol.Type);
  } else {
    if (Symbol.Type & MachO::N_PEXT)
      W.startLine() << "PrivateExtern\n";
    if (Symbol.Type & MachO::N_EXT)
      W.startLine() << "Extern\n";
    W.printEnum("Type", uint8_t(Symbol.Type & MachO::N_TYPE),
                makeArrayRef(MachOSymbolTypes));
  }
  W.printHex   ("Section", SectionName, Symbol.SectionIndex);
  W.printEnum  ("RefType", static_cast<uint16_t>(Symbol.Flags & 0xF),
                  makeArrayRef(MachOSymbolRefTypes));
  W.printFlags ("Flags", static_cast<uint16_t>(Symbol.Flags & ~0xF),
                  makeArrayRef(MachOSymbolFlags));
  W.printHex   ("Value", Symbol.Value);
}

void MachODumper::printUnwindInfo() {
  W.startLine() << "UnwindInfo not implemented.\n";
}
<|endoftext|>


<commit_before>//
//  Particles.cpp
//  Vortex
//

#include "Particles.h"

#include <Vortex2D/Engine/LevelSet.h>

#include <random>
#include "vortex2d_generated_spirv.h"

namespace Vortex2D
{
namespace Fluid
{
float DefaultParticleSize()
{
  return 1.02f / std::sqrtf(2.0f);
}

ParticleCount::ParticleCount(const Renderer::Device& device,
                             const glm::ivec2& size,
                             Renderer::GenericBuffer& particles,
                             Velocity::InterpolationMode interpolationMode,
                             const Renderer::DispatchParams& params,
                             float alpha,
                             float particleSize)
    : Renderer::RenderTexture(device, size.x, size.y, vk::Format::eR32Sint)
    , mDevice(device)
    , mSize(size)
    , mParticles(particles)
    , mNewParticles(device, 8 * size.x * size.y)
    , mDelta(device, size.x * size.y)
    , mCount(device, size.x * size.y)
    , mIndex(device, size.x * size.y)
    , mSeeds(device, 4, VMA_MEMORY_USAGE_CPU_TO_GPU)
    , mDispatchParams(device)
    , mLocalDispatchParams(device, 1, VMA_MEMORY_USAGE_CPU_ONLY)
    , mNewDispatchParams(device)
    , mParticleCountWork(device, Renderer::ComputeSize::Default1D(), SPIRV::ParticleCount_comp)
    , mParticleCountBound(mParticleCountWork.Bind(size, {particles, mDispatchParams, mDelta}))
    , mParticleClampWork(device, size, SPIRV::ParticleClamp_comp)
    , mParticleClampBound(mParticleClampWork.Bind(size, {mDelta}))
    , mPrefixScan(device, size)
    , mPrefixScanBound(mPrefixScan.Bind(mDelta, mIndex, mNewDispatchParams))
    , mParticleBucketWork(device, Renderer::ComputeSize::Default1D(), SPIRV::ParticleBucket_comp)
    , mParticleBucketBound(
          mParticleBucketWork.Bind(size,
                                   {particles, mNewParticles, mIndex, mDelta, mDispatchParams}))
    , mParticleSpawnWork(device, size, SPIRV::ParticleSpawn_comp)
    , mParticleSpawnBound(mParticleSpawnWork.Bind({mNewParticles, mIndex, mDelta, mSeeds}))
    , mParticlePhiWork(device,
                       size,
                       SPIRV::ParticlePhi_comp,
                       Renderer::SpecConst(Renderer::SpecConstValue(3, particleSize)))
    , mParticleToGridWork(device, size, SPIRV::ParticleToGrid_comp)
    , mParticleFromGridWork(device,
                            Renderer::ComputeSize::Default1D(),
                            SPIRV::ParticleFromGrid_comp,
                            Renderer::SpecConst(Renderer::SpecConstValue(3, interpolationMode)))
    , mScanWork(device, false)
    , mDispatchCountWork(device)
    , mParticlePhi(device, false)
    , mParticleToGrid(device, false)
    , mParticleFromGrid(device, false)
    , mAlpha(alpha)
{
  Renderer::CopyFrom(mLocalDispatchParams, params);
  device.Execute([&](vk::CommandBuffer commandBuffer) {
    mDispatchParams.CopyFrom(commandBuffer, mLocalDispatchParams);
  });

  // TODO clamp should be configurable

  // Algorithm
  // 1) copy this to mDelta
  //    -> this sets the number of particles we want to add or remove in each
  //    grid cell
  // 2) for each particle, increase count in grid cell mDelta
  // 3) clamp grid cell of mDelta count between [0, 8]
  //    -> now mDelta contains the number of particles we want in each cell.
  //       which means deleting some or add some
  // 4) copy mDelta to mCount
  //    -> we save the count of particles in mCount as we'll modify mDelta
  // 5) prefix scan from mDelta to mIndex
  //    -> mIndex now maps from grid cell to particle index
  // 6) for each particle, if count in grid cell mDelta > 0, copy to new
  // particles and decrease count
  //    -> using the mIndex mapping to get the index in the new particles buffer
  // 7) for each grid cell mDelta > 0, add new particle in new particles
  //    -> set the new particles with random position
  // 8) copy new particles to particles

  mScanWork.Record([&](vk::CommandBuffer commandBuffer) {
    commandBuffer.debugMarkerBeginEXT({"Particle count", {{0.14f, 0.39f, 0.12f, 1.0f}}},
                                      mDevice.Loader());
    mDelta.CopyFrom(commandBuffer, *this);
    Clear(commandBuffer, std::array<int, 4>{0, 0, 0, 0});
    mParticleCountBound.RecordIndirect(commandBuffer, mDispatchParams);
    mDelta.Barrier(
        commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
    mParticleClampBound.Record(commandBuffer);
    mDelta.Barrier(
        commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
    mCount.CopyFrom(commandBuffer, mDelta);
    commandBuffer.debugMarkerEndEXT(mDevice.Loader());

    commandBuffer.debugMarkerBeginEXT({"Particle scan", {{0.59f, 0.20f, 0.35f, 1.0f}}},
                                      mDevice.Loader());
    mPrefixScanBound.Record(commandBuffer);
    mParticleBucketBound.RecordIndirect(commandBuffer, mDispatchParams);
    mNewParticles.Barrier(
        commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
    mParticleSpawnBound.Record(commandBuffer);
    mNewParticles.Barrier(
        commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
    particles.CopyFrom(commandBuffer, mNewParticles);
    mDispatchParams.CopyFrom(commandBuffer, mNewDispatchParams);
    commandBuffer.debugMarkerEndEXT(mDevice.Loader());
  });

  mDispatchCountWork.Record([&](vk::CommandBuffer commandBuffer) {
    mLocalDispatchParams.CopyFrom(commandBuffer, mDispatchParams);
  });
}

void ParticleCount::Scan()
{
  std::random_device rd;
  std::mt19937 gen(rd());
  std::uniform_int_distribution<> dis;

  std::vector<glm::ivec2> seeds = {
      {dis(gen), dis(gen)}, {dis(gen), dis(gen)}, {dis(gen), dis(gen)}, {dis(gen), dis(gen)}};

  Renderer::CopyFrom(mSeeds, seeds);
  mScanWork.Submit();
}

int ParticleCount::GetTotalCount()
{
  mDispatchCountWork.Submit().Wait();

  Renderer::DispatchParams params(0);
  Renderer::CopyTo(mLocalDispatchParams, params);
  return params.count;
}

Renderer::IndirectBuffer<Renderer::DispatchParams>& ParticleCount::GetDispatchParams()
{
  return mDispatchParams;
}

void ParticleCount::LevelSetBind(LevelSet& levelSet)
{
  // TODO should shrink wrap wholes and redistance
  mParticlePhiBound = mParticlePhiWork.Bind({mCount, mParticles, mIndex, levelSet});
  mParticlePhi.Record([&](vk::CommandBuffer commandBuffer) {
    commandBuffer.debugMarkerBeginEXT({"Particle phi", {{0.86f, 0.72f, 0.29f, 1.0f}}},
                                      mDevice.Loader());
    levelSet.Clear(commandBuffer, std::array<float, 4>{3.0f, 0.0f, 0.0f, 0.0f});
    mParticlePhiBound.Record(commandBuffer);
    levelSet.Barrier(commandBuffer,
                     vk::ImageLayout::eGeneral,
                     vk::AccessFlagBits::eShaderWrite,
                     vk::ImageLayout::eGeneral,
                     vk::AccessFlagBits::eShaderRead);
    commandBuffer.debugMarkerEndEXT(mDevice.Loader());
  });
}

void ParticleCount::Phi()
{
  mParticlePhi.Submit();
}

void ParticleCount::VelocitiesBind(Velocity& velocity, Renderer::GenericBuffer& valid)
{
  mParticleToGridBound = mParticleToGridWork.Bind({mCount, mParticles, mIndex, velocity, valid});
  mParticleToGrid.Record([&](vk::CommandBuffer commandBuffer) {
    commandBuffer.debugMarkerBeginEXT({"Particle to grid", {{0.71f, 0.15f, 0.48f, 1.0f}}},
                                      mDevice.Loader());
    valid.Clear(commandBuffer);
    mParticleToGridBound.Record(commandBuffer);
    valid.Barrier(commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
    commandBuffer.debugMarkerEndEXT(mDevice.Loader());
  });

  mParticleFromGridBound =
      mParticleFromGridWork.Bind({mParticles, mDispatchParams, velocity, velocity.D()});
  mParticleFromGrid.Record([&](vk::CommandBuffer commandBuffer) {
    commandBuffer.debugMarkerBeginEXT({"Particle from grid", {{0.35f, 0.11f, 0.87f, 1.0f}}},
                                      mDevice.Loader());
    mParticleFromGridBound.PushConstant(commandBuffer, mSize.x, mSize.y, mAlpha);
    mParticleFromGridBound.RecordIndirect(commandBuffer, mDispatchParams);
    mParticles.Barrier(
        commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
    commandBuffer.debugMarkerEndEXT(mDevice.Loader());
  });
}

void ParticleCount::TransferToGrid()
{
  mParticleToGrid.Submit();
}

void ParticleCount::TransferFromGrid()
{
  mParticleFromGrid.Submit();
}

}  // namespace Fluid
}  // namespace Vortex2D
<commit_msg>correct sqrt function<commit_after>//
//  Particles.cpp
//  Vortex
//

#include "Particles.h"

#include <Vortex2D/Engine/LevelSet.h>

#include <random>
#include "vortex2d_generated_spirv.h"

namespace Vortex2D
{
namespace Fluid
{
float DefaultParticleSize()
{
  return 1.02f / std::sqrt(2.0f);
}

ParticleCount::ParticleCount(const Renderer::Device& device,
                             const glm::ivec2& size,
                             Renderer::GenericBuffer& particles,
                             Velocity::InterpolationMode interpolationMode,
                             const Renderer::DispatchParams& params,
                             float alpha,
                             float particleSize)
    : Renderer::RenderTexture(device, size.x, size.y, vk::Format::eR32Sint)
    , mDevice(device)
    , mSize(size)
    , mParticles(particles)
    , mNewParticles(device, 8 * size.x * size.y)
    , mDelta(device, size.x * size.y)
    , mCount(device, size.x * size.y)
    , mIndex(device, size.x * size.y)
    , mSeeds(device, 4, VMA_MEMORY_USAGE_CPU_TO_GPU)
    , mDispatchParams(device)
    , mLocalDispatchParams(device, 1, VMA_MEMORY_USAGE_CPU_ONLY)
    , mNewDispatchParams(device)
    , mParticleCountWork(device, Renderer::ComputeSize::Default1D(), SPIRV::ParticleCount_comp)
    , mParticleCountBound(mParticleCountWork.Bind(size, {particles, mDispatchParams, mDelta}))
    , mParticleClampWork(device, size, SPIRV::ParticleClamp_comp)
    , mParticleClampBound(mParticleClampWork.Bind(size, {mDelta}))
    , mPrefixScan(device, size)
    , mPrefixScanBound(mPrefixScan.Bind(mDelta, mIndex, mNewDispatchParams))
    , mParticleBucketWork(device, Renderer::ComputeSize::Default1D(), SPIRV::ParticleBucket_comp)
    , mParticleBucketBound(
          mParticleBucketWork.Bind(size,
                                   {particles, mNewParticles, mIndex, mDelta, mDispatchParams}))
    , mParticleSpawnWork(device, size, SPIRV::ParticleSpawn_comp)
    , mParticleSpawnBound(mParticleSpawnWork.Bind({mNewParticles, mIndex, mDelta, mSeeds}))
    , mParticlePhiWork(device,
                       size,
                       SPIRV::ParticlePhi_comp,
                       Renderer::SpecConst(Renderer::SpecConstValue(3, particleSize)))
    , mParticleToGridWork(device, size, SPIRV::ParticleToGrid_comp)
    , mParticleFromGridWork(device,
                            Renderer::ComputeSize::Default1D(),
                            SPIRV::ParticleFromGrid_comp,
                            Renderer::SpecConst(Renderer::SpecConstValue(3, interpolationMode)))
    , mScanWork(device, false)
    , mDispatchCountWork(device)
    , mParticlePhi(device, false)
    , mParticleToGrid(device, false)
    , mParticleFromGrid(device, false)
    , mAlpha(alpha)
{
  Renderer::CopyFrom(mLocalDispatchParams, params);
  device.Execute([&](vk::CommandBuffer commandBuffer) {
    mDispatchParams.CopyFrom(commandBuffer, mLocalDispatchParams);
  });

  // TODO clamp should be configurable

  // Algorithm
  // 1) copy this to mDelta
  //    -> this sets the number of particles we want to add or remove in each
  //    grid cell
  // 2) for each particle, increase count in grid cell mDelta
  // 3) clamp grid cell of mDelta count between [0, 8]
  //    -> now mDelta contains the number of particles we want in each cell.
  //       which means deleting some or add some
  // 4) copy mDelta to mCount
  //    -> we save the count of particles in mCount as we'll modify mDelta
  // 5) prefix scan from mDelta to mIndex
  //    -> mIndex now maps from grid cell to particle index
  // 6) for each particle, if count in grid cell mDelta > 0, copy to new
  // particles and decrease count
  //    -> using the mIndex mapping to get the index in the new particles buffer
  // 7) for each grid cell mDelta > 0, add new particle in new particles
  //    -> set the new particles with random position
  // 8) copy new particles to particles

  mScanWork.Record([&](vk::CommandBuffer commandBuffer) {
    commandBuffer.debugMarkerBeginEXT({"Particle count", {{0.14f, 0.39f, 0.12f, 1.0f}}},
                                      mDevice.Loader());
    mDelta.CopyFrom(commandBuffer, *this);
    Clear(commandBuffer, std::array<int, 4>{0, 0, 0, 0});
    mParticleCountBound.RecordIndirect(commandBuffer, mDispatchParams);
    mDelta.Barrier(
        commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
    mParticleClampBound.Record(commandBuffer);
    mDelta.Barrier(
        commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
    mCount.CopyFrom(commandBuffer, mDelta);
    commandBuffer.debugMarkerEndEXT(mDevice.Loader());

    commandBuffer.debugMarkerBeginEXT({"Particle scan", {{0.59f, 0.20f, 0.35f, 1.0f}}},
                                      mDevice.Loader());
    mPrefixScanBound.Record(commandBuffer);
    mParticleBucketBound.RecordIndirect(commandBuffer, mDispatchParams);
    mNewParticles.Barrier(
        commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
    mParticleSpawnBound.Record(commandBuffer);
    mNewParticles.Barrier(
        commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
    particles.CopyFrom(commandBuffer, mNewParticles);
    mDispatchParams.CopyFrom(commandBuffer, mNewDispatchParams);
    commandBuffer.debugMarkerEndEXT(mDevice.Loader());
  });

  mDispatchCountWork.Record([&](vk::CommandBuffer commandBuffer) {
    mLocalDispatchParams.CopyFrom(commandBuffer, mDispatchParams);
  });
}

void ParticleCount::Scan()
{
  std::random_device rd;
  std::mt19937 gen(rd());
  std::uniform_int_distribution<> dis;

  std::vector<glm::ivec2> seeds = {
      {dis(gen), dis(gen)}, {dis(gen), dis(gen)}, {dis(gen), dis(gen)}, {dis(gen), dis(gen)}};

  Renderer::CopyFrom(mSeeds, seeds);
  mScanWork.Submit();
}

int ParticleCount::GetTotalCount()
{
  mDispatchCountWork.Submit().Wait();

  Renderer::DispatchParams params(0);
  Renderer::CopyTo(mLocalDispatchParams, params);
  return params.count;
}

Renderer::IndirectBuffer<Renderer::DispatchParams>& ParticleCount::GetDispatchParams()
{
  return mDispatchParams;
}

void ParticleCount::LevelSetBind(LevelSet& levelSet)
{
  // TODO should shrink wrap wholes and redistance
  mParticlePhiBound = mParticlePhiWork.Bind({mCount, mParticles, mIndex, levelSet});
  mParticlePhi.Record([&](vk::CommandBuffer commandBuffer) {
    commandBuffer.debugMarkerBeginEXT({"Particle phi", {{0.86f, 0.72f, 0.29f, 1.0f}}},
                                      mDevice.Loader());
    levelSet.Clear(commandBuffer, std::array<float, 4>{3.0f, 0.0f, 0.0f, 0.0f});
    mParticlePhiBound.Record(commandBuffer);
    levelSet.Barrier(commandBuffer,
                     vk::ImageLayout::eGeneral,
                     vk::AccessFlagBits::eShaderWrite,
                     vk::ImageLayout::eGeneral,
                     vk::AccessFlagBits::eShaderRead);
    commandBuffer.debugMarkerEndEXT(mDevice.Loader());
  });
}

void ParticleCount::Phi()
{
  mParticlePhi.Submit();
}

void ParticleCount::VelocitiesBind(Velocity& velocity, Renderer::GenericBuffer& valid)
{
  mParticleToGridBound = mParticleToGridWork.Bind({mCount, mParticles, mIndex, velocity, valid});
  mParticleToGrid.Record([&](vk::CommandBuffer commandBuffer) {
    commandBuffer.debugMarkerBeginEXT({"Particle to grid", {{0.71f, 0.15f, 0.48f, 1.0f}}},
                                      mDevice.Loader());
    valid.Clear(commandBuffer);
    mParticleToGridBound.Record(commandBuffer);
    valid.Barrier(commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
    commandBuffer.debugMarkerEndEXT(mDevice.Loader());
  });

  mParticleFromGridBound =
      mParticleFromGridWork.Bind({mParticles, mDispatchParams, velocity, velocity.D()});
  mParticleFromGrid.Record([&](vk::CommandBuffer commandBuffer) {
    commandBuffer.debugMarkerBeginEXT({"Particle from grid", {{0.35f, 0.11f, 0.87f, 1.0f}}},
                                      mDevice.Loader());
    mParticleFromGridBound.PushConstant(commandBuffer, mSize.x, mSize.y, mAlpha);
    mParticleFromGridBound.RecordIndirect(commandBuffer, mDispatchParams);
    mParticles.Barrier(
        commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
    commandBuffer.debugMarkerEndEXT(mDevice.Loader());
  });
}

void ParticleCount::TransferToGrid()
{
  mParticleToGrid.Submit();
}

void ParticleCount::TransferFromGrid()
{
  mParticleFromGrid.Submit();
}

}  // namespace Fluid
}  // namespace Vortex2D
<|endoftext|>


<commit_before>// //////////////////////////////////////////////////////////////////////
// Import section
// //////////////////////////////////////////////////////////////////////
// STL
#include <cassert>
#include <istream>
#include <ostream>
#include <sstream>
#include <iomanip>
// StdAir
#include <stdair/bom/AirlineFeatureSet.hpp>
#include <stdair/basic/BasChronometer.hpp>
#include <stdair/basic/BasFileMgr.hpp>
#include <stdair/bom/BomManager.hpp> // for display()
#include <stdair/service/Logger.hpp>
// AIRSCHED
#include <airsched/basic/BasConst_AIRSCHED_Service.hpp>
#include <airsched/bom/BomRoot.hpp>
#include <airsched/factory/FacAIRSCHEDServiceContext.hpp>
#include <airsched/command/Simulator.hpp>
#include <airsched/command/ScheduleParser.hpp>
#include <airsched/command/NetworkGenerator.hpp>
#include <airsched/service/AIRSCHED_ServiceContext.hpp>
#include <airsched/AIRSCHED_Service.hpp>

namespace AIRSCHED {

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::AIRSCHED_Service () : _airschedServiceContext (NULL) {
    assert (false);
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::AIRSCHED_Service (const AIRSCHED_Service& iService) {
    assert (false);
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::
  AIRSCHED_Service (const stdair::AirlineFeatureSet& iAirlineFeatureSet,
                    const stdair::Date_T& iStartAnalysisDate,
                    const stdair::Filename_T& iScheduleInputFilename)
    : _airschedServiceContext (NULL) {
    // Initialise the context
    init (iAirlineFeatureSet, iStartAnalysisDate, iScheduleInputFilename);
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::
  AIRSCHED_Service (const stdair::BasLogParams& iLogParams,
                    const stdair::AirlineFeatureSet& iAirlineFeatureSet,
                    const stdair::Date_T& iStartAnalysisDate,
                    const stdair::Filename_T& iScheduleInputFilename)
    : _airschedServiceContext (NULL) {

    // Set the log file
    logInit (iLogParams);

    // Initialise the (remaining of the) context
    init (iAirlineFeatureSet, iStartAnalysisDate, iScheduleInputFilename);
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::~AIRSCHED_Service () {
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::logInit (const stdair::BasLogParams& iLogParams) {
    stdair::Logger::init (iLogParams);
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::
  init (const stdair::AirlineFeatureSet& iAirlineFeatureSet,
        const stdair::Date_T& iStartAnalysisDate,
        const stdair::Filename_T& iScheduleInputFilename) {

    // Check that the file path given as input corresponds to an actual file
    const bool doesExistAndIsReadable =
      stdair::BasFileMgr::doesExistAndIsReadable (iScheduleInputFilename);
    if (doesExistAndIsReadable == false) {
      STDAIR_LOG_ERROR ("The schedule input file, '" << iScheduleInputFilename
                        << "', can not be retrieved on the file-system");
      throw FileNotFoundException();
    }

    // Initialise the context
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      FacAIRSCHEDServiceContext::instance().create ();
    _airschedServiceContext = &lAIRSCHED_ServiceContext;

    // Store the AirlineFeatureSet object within the service context
    lAIRSCHED_ServiceContext.setAirlineFeatureSet (iAirlineFeatureSet);

    // Store the beginning date of analysis within the service context
    lAIRSCHED_ServiceContext.setStartAnalysisDate (iStartAnalysisDate);

    // Parse the schedule input file, and generate the Inventories
    stdair::BomRoot& oBomRoot =
      ScheduleParser::generateInventories (iScheduleInputFilename,
                                           iAirlineFeatureSet,
                                           iStartAnalysisDate);

    // Build the network from the schedule.
    NetworkGenerator::createNetworks (oBomRoot);

    // Store the BOM object tree within the service context
    lAIRSCHED_ServiceContext.setBomRoot (oBomRoot);

    // DEBUG
    STDAIR_LOG_DEBUG ("Generated BomRoot:");
    std::ostringstream oStream;
    stdair::BomManager::display (oStream, oBomRoot);
    STDAIR_LOG_DEBUG (oStream.str());
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::
  addTravelSolution (const stdair::AirportCode_T& iDepartureAirport,
                     const stdair::AirportCode_T& iArrivalAirport,
                     const stdair::Date_T& iDepartureDate,
                     const stdair::Duration_T& iDepartureTime,
                     const stdair::Duration_T& iArrivalTime,
                     const stdair::Duration_T& iDuration,
                     const bool iRefundability,
                     const stdair::AirlineCode_T& iAirlineCode,
                     const stdair::CabinCode_T& iCabinCode,
                     const stdair::FlightNumber_T& iFlightNumber,
                     const stdair::Fare_T& iFare,
                     int iStopsNumber, bool iSNS, bool iChangeability) {

    if (_airschedServiceContext == NULL) {
      throw NonInitialisedServiceException();
    }
    assert (_airschedServiceContext != NULL);
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext= *_airschedServiceContext;

    // Add the travel solution to the service context
    lAIRSCHED_ServiceContext.addTravelSolution (iDepartureAirport,
                                                iArrivalAirport, iDepartureDate,
                                                iDepartureTime, iArrivalTime,
                                                iDuration, iRefundability,
                                                iAirlineCode, iCabinCode,
                                                iFlightNumber, iFare,
                                                iStopsNumber, iSNS,
                                                iChangeability);
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::simulate()  {

    if (_airschedServiceContext == NULL) {
      throw NonInitialisedServiceException();
    }
    assert (_airschedServiceContext != NULL);
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext= *_airschedServiceContext;

    // Retrieve, from the service context, the root of the BOM tree
    stdair::BomRoot& lBomRoot = lAIRSCHED_ServiceContext.getBomRoot();

    // Call the underlying Use Case (command)
    stdair::BasChronometer lSimulateChronometer;
    lSimulateChronometer.start();
    Simulator::simulate (lBomRoot);
    const double lSimulateMeasure = lSimulateChronometer.elapsed();

    // DEBUG
    STDAIR_LOG_DEBUG ("Simulation: " << lSimulateMeasure << " - "
                      << lAIRSCHED_ServiceContext.display());
  }

  // ////////////////////////////////////////////////////////////////////
  stdair::OutboundPathLightList_T AIRSCHED_Service::
  getTravelSolutions (const stdair::BookingRequestStruct& iBookingRequest) {
    // Initiate an empty list of outbound paths/travel solutions.
    stdair::OutboundPathLightList_T oOutboundPathList;

    return oOutboundPathList;
  }

}
<commit_msg>[Dev] Making a sale.<commit_after>// //////////////////////////////////////////////////////////////////////
// Import section
// //////////////////////////////////////////////////////////////////////
// STL
#include <cassert>
#include <istream>
#include <ostream>
#include <sstream>
#include <iomanip>
// StdAir
#include <stdair/bom/AirlineFeatureSet.hpp>
#include <stdair/basic/BasChronometer.hpp>
#include <stdair/basic/BasFileMgr.hpp>
#include <stdair/bom/BomManager.hpp> // for display()
#include <stdair/service/Logger.hpp>
// AIRSCHED
#include <airsched/basic/BasConst_AIRSCHED_Service.hpp>
#include <airsched/bom/BomRoot.hpp>
#include <airsched/factory/FacAIRSCHEDServiceContext.hpp>
#include <airsched/command/Simulator.hpp>
#include <airsched/command/ScheduleParser.hpp>
#include <airsched/command/NetworkGenerator.hpp>
#include <airsched/service/AIRSCHED_ServiceContext.hpp>
#include <airsched/AIRSCHED_Service.hpp>

namespace AIRSCHED {

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::AIRSCHED_Service () : _airschedServiceContext (NULL) {
    assert (false);
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::AIRSCHED_Service (const AIRSCHED_Service& iService) {
    assert (false);
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::
  AIRSCHED_Service (const stdair::AirlineFeatureSet& iAirlineFeatureSet,
                    const stdair::Date_T& iStartAnalysisDate,
                    const stdair::Filename_T& iScheduleInputFilename)
    : _airschedServiceContext (NULL) {
    // Initialise the context
    init (iAirlineFeatureSet, iStartAnalysisDate, iScheduleInputFilename);
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::
  AIRSCHED_Service (const stdair::BasLogParams& iLogParams,
                    const stdair::AirlineFeatureSet& iAirlineFeatureSet,
                    const stdair::Date_T& iStartAnalysisDate,
                    const stdair::Filename_T& iScheduleInputFilename)
    : _airschedServiceContext (NULL) {

    // Set the log file
    logInit (iLogParams);

    // Initialise the (remaining of the) context
    init (iAirlineFeatureSet, iStartAnalysisDate, iScheduleInputFilename);
  }

  // ////////////////////////////////////////////////////////////////////
  AIRSCHED_Service::~AIRSCHED_Service () {
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::logInit (const stdair::BasLogParams& iLogParams) {
    stdair::Logger::init (iLogParams);
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::
  init (const stdair::AirlineFeatureSet& iAirlineFeatureSet,
        const stdair::Date_T& iStartAnalysisDate,
        const stdair::Filename_T& iScheduleInputFilename) {

    // Check that the file path given as input corresponds to an actual file
    const bool doesExistAndIsReadable =
      stdair::BasFileMgr::doesExistAndIsReadable (iScheduleInputFilename);
    if (doesExistAndIsReadable == false) {
      STDAIR_LOG_ERROR ("The schedule input file, '" << iScheduleInputFilename
                        << "', can not be retrieved on the file-system");
      throw FileNotFoundException();
    }

    // Initialise the context
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext =
      FacAIRSCHEDServiceContext::instance().create ();
    _airschedServiceContext = &lAIRSCHED_ServiceContext;

    // Store the AirlineFeatureSet object within the service context
    lAIRSCHED_ServiceContext.setAirlineFeatureSet (iAirlineFeatureSet);

    // Store the beginning date of analysis within the service context
    lAIRSCHED_ServiceContext.setStartAnalysisDate (iStartAnalysisDate);

    // Parse the schedule input file, and generate the Inventories
    stdair::BomRoot& oBomRoot =
      ScheduleParser::generateInventories (iScheduleInputFilename,
                                           iAirlineFeatureSet,
                                           iStartAnalysisDate);

    // Build the network from the schedule.
    NetworkGenerator::createNetworks (oBomRoot);

    // Store the BOM object tree within the service context
    lAIRSCHED_ServiceContext.setBomRoot (oBomRoot);

    // DEBUG
    STDAIR_LOG_DEBUG ("Generated BomRoot:");
    std::ostringstream oStream;
    stdair::BomManager::display (oStream, oBomRoot);
    STDAIR_LOG_DEBUG (oStream.str());
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::
  addTravelSolution (const stdair::AirportCode_T& iDepartureAirport,
                     const stdair::AirportCode_T& iArrivalAirport,
                     const stdair::Date_T& iDepartureDate,
                     const stdair::Duration_T& iDepartureTime,
                     const stdair::Duration_T& iArrivalTime,
                     const stdair::Duration_T& iDuration,
                     const bool iRefundability,
                     const stdair::AirlineCode_T& iAirlineCode,
                     const stdair::CabinCode_T& iCabinCode,
                     const stdair::FlightNumber_T& iFlightNumber,
                     const stdair::Fare_T& iFare,
                     int iStopsNumber, bool iSNS, bool iChangeability) {

    if (_airschedServiceContext == NULL) {
      throw NonInitialisedServiceException();
    }
    assert (_airschedServiceContext != NULL);
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext= *_airschedServiceContext;

    // Add the travel solution to the service context
    lAIRSCHED_ServiceContext.addTravelSolution (iDepartureAirport,
                                                iArrivalAirport, iDepartureDate,
                                                iDepartureTime, iArrivalTime,
                                                iDuration, iRefundability,
                                                iAirlineCode, iCabinCode,
                                                iFlightNumber, iFare,
                                                iStopsNumber, iSNS,
                                                iChangeability);
  }

  // ////////////////////////////////////////////////////////////////////
  void AIRSCHED_Service::simulate()  {

    if (_airschedServiceContext == NULL) {
      throw NonInitialisedServiceException();
    }
    assert (_airschedServiceContext != NULL);
    AIRSCHED_ServiceContext& lAIRSCHED_ServiceContext= *_airschedServiceContext;

    // Retrieve, from the service context, the root of the BOM tree
    stdair::BomRoot& lBomRoot = lAIRSCHED_ServiceContext.getBomRoot();

    // Call the underlying Use Case (command)
    stdair::BasChronometer lSimulateChronometer;
    lSimulateChronometer.start();
    Simulator::simulate (lBomRoot);
    const double lSimulateMeasure = lSimulateChronometer.elapsed();

    // DEBUG
    STDAIR_LOG_DEBUG ("Simulation: " << lSimulateMeasure << " - "
                      << lAIRSCHED_ServiceContext.display());
  }

  // ////////////////////////////////////////////////////////////////////
  stdair::OutboundPathLightList_T AIRSCHED_Service::
  getTravelSolutions (const stdair::BookingRequestStruct& iBookingRequest) {
    // Initiate an empty list of outbound paths/travel solutions.
    stdair::OutboundPathLightList_T oOutboundPathList;

    return oOutboundPathList;
  }

}
<|endoftext|>


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

#include <memory>
#include "com/centreon/broker/bam/connector.hh"
#include "com/centreon/broker/bam/factory.hh"
#include "com/centreon/broker/config/parser.hh"
#include "com/centreon/broker/database_config.hh"
#include "com/centreon/broker/exceptions/msg.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::bam;

/**************************************
*                                     *
*           Static Objects            *
*                                     *
**************************************/

/**
 *  Find a parameter in configuration.
 *
 *  @param[in] cfg Configuration object.
 *  @param[in] key Property to get.
 *
 *  @return Property value.
 */
static QString const& find_param(
                        config::endpoint const& cfg,
                        QString const& key) {
  QMap<QString, QString>::const_iterator it(cfg.params.find(key));
  if (cfg.params.end() == it)
    throw (exceptions::msg() << "BAM: no '" << key
           << "' defined for endpoint '" << cfg.name << "'");
  return (it.value());
}

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Default constructor.
 */
factory::factory() {}

/**
 *  Copy constructor.
 *
 *  @param[in] other  Object to copy.
 */
factory::factory(factory const& other) : io::factory(other) {}

/**
 *  Destructor.
 */
factory::~factory() {}

/**
 *  Assignment operator.
 *
 *  @param[in] other  Object to copy.
 *
 *  @return This object.
 */
factory& factory::operator=(factory const& other) {
  io::factory::operator=(other);
  return (*this);
}

/**
 *  Clone this object.
 *
 *  @return Exact copy of this factory.
 */
io::factory* factory::clone() const {
  return (new factory(*this));
}

/**
 *  Check if a configuration match the BAM layer.
 *
 *  @param[in] cfg  Endpoint configuration.
 *
 *  @return True if the configuration matches the BAM layer.
 */
bool factory::has_endpoint(config::endpoint& cfg) const {
  bool is_bam(!cfg.type.compare("bam", Qt::CaseInsensitive));
  bool is_bam_bi(!cfg.type.compare("bam_bi", Qt::CaseInsensitive));
  if (is_bam || is_bam_bi) {
    cfg.params["read_timeout"] = "1";
    cfg.read_timeout = 1;
  }
  return (is_bam || is_bam_bi);
}

/**
 *  Build a BAM endpoint from a configuration.
 *
 *  @param[in]  cfg         Endpoint configuration.
 *  @param[out] is_acceptor Will be set to false.
 *  @param[in]  cache       Unused.
 *
 *  @return Endpoint matching the given configuration.
 */
io::endpoint* factory::new_endpoint(
                         config::endpoint& cfg,
                         bool& is_acceptor,
                         misc::shared_ptr<persistent_cache> cache) const {
  (void)cache;

  // Find DB parameters.
  database_config db_cfg;
  db_cfg.set_type(find_param(cfg, "db_type").toStdString());
  db_cfg.set_host(find_param(cfg, "db_host").toStdString());
  db_cfg.set_port(find_param(cfg, "db_port").toUShort());
  db_cfg.set_user(find_param(cfg, "db_user").toStdString());
  db_cfg.set_password(find_param(cfg, "db_password").toStdString());
  db_cfg.set_name(find_param(cfg, "db_name").toStdString());

  // Transaction size.
  unsigned int queries_per_transaction(0);
  {
    QMap<QString, QString>::const_iterator
      it(cfg.params.find("queries_per_transaction"));
    if (it != cfg.params.end())
      queries_per_transaction = it.value().toUInt();
    else
      queries_per_transaction = 1000;
  }
  db_cfg.set_queries_per_transaction(queries_per_transaction);

  // Check replication status ?
  bool check_replication(true);
  {
    QMap<QString, QString>::const_iterator
      it(cfg.params.find("check_replication"));
    if (it != cfg.params.end())
      check_replication = config::parser::parse_boolean(*it);
  }
  db_cfg.set_check_replication(check_replication);

  // Is it a BAM or BAM-BI output ?
  bool is_bam_bi(!cfg.type.compare("bam_bi", Qt::CaseInsensitive));

  // Storage database name.
  std::string storage_db_name;
  {
    QMap<QString, QString>::const_iterator
      it(cfg.params.find("storage_db_name"));
    if (it != cfg.params.end())
      storage_db_name = it->toStdString();
  }

  // Connector.
  std::auto_ptr<bam::connector> c(new bam::connector);
  if (is_bam_bi)
    c->connect_reporting(db_cfg);
  else
    c->connect_monitoring(db_cfg, storage_db_name);
  is_acceptor = false;
  return (c.release());
}
<commit_msg>BAM: set database configuration using directly database_config object.<commit_after>/*
** Copyright 2014-2015 Centreon
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
**
** For more information : contact@centreon.com
*/

#include <memory>
#include "com/centreon/broker/bam/connector.hh"
#include "com/centreon/broker/bam/factory.hh"
#include "com/centreon/broker/config/parser.hh"
#include "com/centreon/broker/database_config.hh"
#include "com/centreon/broker/exceptions/msg.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::bam;

/**************************************
*                                     *
*           Static Objects            *
*                                     *
**************************************/

/**
 *  Find a parameter in configuration.
 *
 *  @param[in] cfg Configuration object.
 *  @param[in] key Property to get.
 *
 *  @return Property value.
 */
static QString const& find_param(
                        config::endpoint const& cfg,
                        QString const& key) {
  QMap<QString, QString>::const_iterator it(cfg.params.find(key));
  if (cfg.params.end() == it)
    throw (exceptions::msg() << "BAM: no '" << key
           << "' defined for endpoint '" << cfg.name << "'");
  return (it.value());
}

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Default constructor.
 */
factory::factory() {}

/**
 *  Copy constructor.
 *
 *  @param[in] other  Object to copy.
 */
factory::factory(factory const& other) : io::factory(other) {}

/**
 *  Destructor.
 */
factory::~factory() {}

/**
 *  Assignment operator.
 *
 *  @param[in] other  Object to copy.
 *
 *  @return This object.
 */
factory& factory::operator=(factory const& other) {
  io::factory::operator=(other);
  return (*this);
}

/**
 *  Clone this object.
 *
 *  @return Exact copy of this factory.
 */
io::factory* factory::clone() const {
  return (new factory(*this));
}

/**
 *  Check if a configuration match the BAM layer.
 *
 *  @param[in] cfg  Endpoint configuration.
 *
 *  @return True if the configuration matches the BAM layer.
 */
bool factory::has_endpoint(config::endpoint& cfg) const {
  bool is_bam(!cfg.type.compare("bam", Qt::CaseInsensitive));
  bool is_bam_bi(!cfg.type.compare("bam_bi", Qt::CaseInsensitive));
  if (is_bam || is_bam_bi) {
    cfg.params["read_timeout"] = "1";
    cfg.read_timeout = 1;
  }
  return (is_bam || is_bam_bi);
}

/**
 *  Build a BAM endpoint from a configuration.
 *
 *  @param[in]  cfg         Endpoint configuration.
 *  @param[out] is_acceptor Will be set to false.
 *  @param[in]  cache       Unused.
 *
 *  @return Endpoint matching the given configuration.
 */
io::endpoint* factory::new_endpoint(
                         config::endpoint& cfg,
                         bool& is_acceptor,
                         misc::shared_ptr<persistent_cache> cache) const {
  (void)cache;

  // Find DB parameters.
  database_config db_cfg(cfg);

  // Is it a BAM or BAM-BI output ?
  bool is_bam_bi(!cfg.type.compare("bam_bi", Qt::CaseInsensitive));

  // Storage database name.
  std::string storage_db_name;
  {
    QMap<QString, QString>::const_iterator
      it(cfg.params.find("storage_db_name"));
    if (it != cfg.params.end())
      storage_db_name = it->toStdString();
  }

  // Connector.
  std::auto_ptr<bam::connector> c(new bam::connector);
  if (is_bam_bi)
    c->connect_reporting(db_cfg);
  else
    c->connect_monitoring(db_cfg, storage_db_name);
  is_acceptor = false;
  return (c.release());
}
<|endoftext|>