<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (testabilitydriver@nokia.com)
**
** This file is part of Testability Driver Qt Agent
**
** If you have questions regarding the use of this file, please contact
** Nokia at testabilitydriver@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 <QtPlugin>
#include <QDebug>

#include <testabilityutils.h>
#include <taslogger.h>
#include "tasqttraverse.h"

Q_EXPORT_PLUGIN2(qttraverse, TasQtTraverse)

/*!
    \class TasQtTraverse
    \brief TasQtTraverse traverse QWidgets and QGraphicsItems

    Traverse the basic qt ui elements
*/

/*!
    Constructor
*/
TasQtTraverse::TasQtTraverse(QObject* parent)
    :QObject(parent)
{
    mTraverseUtils = new TasTraverseUtils();
}

/*!
    Destructor
*/
TasQtTraverse::~TasQtTraverse()
{
    delete mTraverseUtils;
}

void TasQtTraverse::beginTraverse(TasCommand* command)
{
    mTraverseUtils->createFilter(command);
}

void TasQtTraverse::endTraverse()
{
    mTraverseUtils->clearFilter();
}

/*!
  Traverse QGraphicsItem based objects.
 */
void TasQtTraverse::traverseGraphicsItem(TasObject* objectInfo, QGraphicsItem* graphicsItem, TasCommand* command)
{
    bool embeddedApp = false;
    if (command && command->parameter("embedded") == "true") {
        embeddedApp = true;
    }

    objectInfo->addAttribute("objectType", embeddedApp? TYPE_WEB : TYPE_GRAPHICS_VIEW);
    objectInfo->setId(TestabilityUtils::graphicsItemId(graphicsItem));
    mTraverseUtils->addGraphicsItemCoordinates(objectInfo, graphicsItem, command);
    mTraverseUtils->printGraphicsItemProperties(objectInfo, graphicsItem);

}

/*!
  Traverse QObject based items.
*/
void TasQtTraverse::traverseObject(TasObject* objectInfo, QObject* object, TasCommand* command)
{
     // Embedded apps must use coordinates for operations, as the parent has no knowledge of the
    // Actual items
    bool embeddedApp = false;
    if (command && command->parameter("embedded") == "true") {
        embeddedApp = true;
    }
    //TasLogger::logger()->debug("TasQtTraverse::traverseObject in");
    mTraverseUtils->addObjectDetails(objectInfo, object);
    QGraphicsObject* graphicsObject = qobject_cast<QGraphicsObject*>(object);
    if(graphicsObject){
        objectInfo->addAttribute("objectType", embeddedApp? TYPE_WEB : TYPE_GRAPHICS_VIEW);
        mTraverseUtils->addGraphicsItemCoordinates(objectInfo, graphicsObject, command);
        mTraverseUtils->printGraphicsItemProperties(objectInfo, graphicsObject);

        //add details only for graphicsitems
        QGraphicsWidget* graphicsWidget = qobject_cast<QGraphicsWidget*>(object);
        if(graphicsWidget){
            mTraverseUtils->addFont(objectInfo, graphicsWidget->font());
            // Elided format "this is a text" -> "this is a..." text for
            // items that have the "text" property.
            QVariant text = graphicsWidget->property("text");
            if (text.isValid()) {
                mTraverseUtils->addTextInfo(objectInfo, text.toString(), graphicsWidget->font(), graphicsWidget->size().width());

            }
            QVariant plainText = graphicsWidget->property("plainText");
            if (plainText.isValid()) {
                mTraverseUtils->addTextInfo(objectInfo, plainText.toString(), graphicsWidget->font(), graphicsWidget->size().width());
            }
        }
    }
    else{
        //make sure that we are dealing with a widget
        if (object->isWidgetType()){
            QWidget* widget = qobject_cast<QWidget*>(object);
            objectInfo->addAttribute("objectType", TYPE_STANDARD_VIEW );

            addWidgetCoordinates(objectInfo, widget,command);
            mTraverseUtils->addFont(objectInfo, widget->font());
            //check is the widget a viewport to graphicsscene
            QWidget* parentWidget = widget->parentWidget();
            bool isViewPort = false;
            if(parentWidget && parentWidget->inherits("QGraphicsView")){
                QGraphicsView* view = qobject_cast<QGraphicsView*>(parentWidget);
                if(view->viewport() == widget){
                    isViewPort = true;
                }
            }
            //add transformation details
            QGraphicsView* graphicsView = qobject_cast<QGraphicsView*>(object);
            if(graphicsView){
                objectInfo->addBooleanAttribute("isTransformed", graphicsView->isTransformed());
                if(graphicsView->isTransformed()){
                    QTransform tr = graphicsView->transform();
                    objectInfo->addAttribute("transformM11",tr.m11());
                    objectInfo->addAttribute("transformM12",tr.m12());
                    objectInfo->addAttribute("transformM13",tr.m13());
                    objectInfo->addAttribute("transformM21",tr.m21());
                    objectInfo->addAttribute("transformM22",tr.m22());
                    objectInfo->addAttribute("transformM23",tr.m23());
                    objectInfo->addAttribute("transformM31",tr.m31());
                    objectInfo->addAttribute("transformM32",tr.m32());
                    objectInfo->addAttribute("transformM33",tr.m33());
                }
            }
            objectInfo->addBooleanAttribute("isViewPort", isViewPort);
// Add special window id attribute into qwidget atttributes
#if defined(Q_WS_X11)
            unsigned long wid = static_cast<unsigned long>(widget->winId());
            objectInfo->addAttribute("xWindow", (int)wid); // can this fail due to precision?
#endif

        } else {
            if(object != qApp){
                objectInfo->addAttribute("objectType", embeddedApp? TYPE_WEB : TYPE_STANDARD_VIEW );
            }
        }

    }
}

void TasQtTraverse::addWidgetCoordinates(TasObject* objectInfo, QWidget* widget, TasCommand* command)
{
    objectInfo->addBooleanAttribute("isWindow", widget->isWindow());

    QGraphicsProxyWidget* proxy = TestabilityUtils::parentProxy(widget);
    if (proxy) {
        //TasLogger::logger()->debug("TasQtTraverse::addWidgetCoordinates got proxy");
        //print window coordinates

        QRectF sceneRect = proxy->sceneBoundingRect();
        QGraphicsView* view = TestabilityUtils::getViewForItem(proxy);
        if(!view->viewportTransform().isIdentity()){
            QTransform transform = view->viewportTransform();
            sceneRect = transform.mapRect(sceneRect);
        }
        QPoint point = sceneRect.topLeft().toPoint();

        //Print screen coordinates
        QPoint windowPoint = widget->mapTo(widget->window(),QPoint(0, 0));
        windowPoint += point;
        objectInfo->addAttribute("x", windowPoint.x());
        objectInfo->addAttribute("y", windowPoint.y());

        objectInfo->addAttribute("x_absolute", windowPoint.x());
        objectInfo->addAttribute("y_absolute", windowPoint.y());
    }
    else {
        QPoint screenPoint;
        if (command && command->parameter("x_parent_absolute") != "" &&
            command->parameter("y_parent_absolute") != "") {
            //TasLogger::logger()->debug("TasQtTraverse::addWidgetCoordinates moving point");
            QPoint p(command->parameter("x_parent_absolute").toInt(),
                     command->parameter("y_parent_absolute").toInt());
            screenPoint = widget->mapToGlobal(p);

            objectInfo->addAttribute("x_absolute", screenPoint.x());
            objectInfo->addAttribute("y_absolute", screenPoint.y());

        } else {
            //TasLogger::logger()->debug("TasQtTraverse::addWidgetCoordinates using regular coords");
            screenPoint = widget->mapToGlobal(QPoint(0, 0));
            objectInfo->addAttribute("x_absolute", screenPoint.x());
            objectInfo->addAttribute("y_absolute", screenPoint.y());
        }
         //print window coordinates

        QPoint windowPoint = widget->window()->mapFromGlobal(screenPoint);
        objectInfo->addAttribute("x", windowPoint.x());
        objectInfo->addAttribute("y", windowPoint.y());

    }
    // Explicitly add width and height (property added changes name)
    objectInfo->addAttribute("width", widget->width());
    objectInfo->addAttribute("height", widget->height());
}

<commit_msg>use effectiveWinId instead of winId<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (testabilitydriver@nokia.com)
**
** This file is part of Testability Driver Qt Agent
**
** If you have questions regarding the use of this file, please contact
** Nokia at testabilitydriver@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 <QtPlugin>
#include <QDebug>

#include <testabilityutils.h>
#include <taslogger.h>
#include "tasqttraverse.h"

Q_EXPORT_PLUGIN2(qttraverse, TasQtTraverse)

/*!
    \class TasQtTraverse
    \brief TasQtTraverse traverse QWidgets and QGraphicsItems

    Traverse the basic qt ui elements
*/

/*!
    Constructor
*/
TasQtTraverse::TasQtTraverse(QObject* parent)
    :QObject(parent)
{
    mTraverseUtils = new TasTraverseUtils();
}

/*!
    Destructor
*/
TasQtTraverse::~TasQtTraverse()
{
    delete mTraverseUtils;
}

void TasQtTraverse::beginTraverse(TasCommand* command)
{
    mTraverseUtils->createFilter(command);
}

void TasQtTraverse::endTraverse()
{
    mTraverseUtils->clearFilter();
}

/*!
  Traverse QGraphicsItem based objects.
 */
void TasQtTraverse::traverseGraphicsItem(TasObject* objectInfo, QGraphicsItem* graphicsItem, TasCommand* command)
{
    bool embeddedApp = false;
    if (command && command->parameter("embedded") == "true") {
        embeddedApp = true;
    }

    objectInfo->addAttribute("objectType", embeddedApp? TYPE_WEB : TYPE_GRAPHICS_VIEW);
    objectInfo->setId(TestabilityUtils::graphicsItemId(graphicsItem));
    mTraverseUtils->addGraphicsItemCoordinates(objectInfo, graphicsItem, command);
    mTraverseUtils->printGraphicsItemProperties(objectInfo, graphicsItem);

}

/*!
  Traverse QObject based items.
*/
void TasQtTraverse::traverseObject(TasObject* objectInfo, QObject* object, TasCommand* command)
{
     // Embedded apps must use coordinates for operations, as the parent has no knowledge of the
    // Actual items
    bool embeddedApp = false;
    if (command && command->parameter("embedded") == "true") {
        embeddedApp = true;
    }
    //TasLogger::logger()->debug("TasQtTraverse::traverseObject in");
    mTraverseUtils->addObjectDetails(objectInfo, object);
    QGraphicsObject* graphicsObject = qobject_cast<QGraphicsObject*>(object);
    if(graphicsObject){
        objectInfo->addAttribute("objectType", embeddedApp? TYPE_WEB : TYPE_GRAPHICS_VIEW);
        mTraverseUtils->addGraphicsItemCoordinates(objectInfo, graphicsObject, command);
        mTraverseUtils->printGraphicsItemProperties(objectInfo, graphicsObject);

        //add details only for graphicsitems
        QGraphicsWidget* graphicsWidget = qobject_cast<QGraphicsWidget*>(object);
        if(graphicsWidget){
            mTraverseUtils->addFont(objectInfo, graphicsWidget->font());
            // Elided format "this is a text" -> "this is a..." text for
            // items that have the "text" property.
            QVariant text = graphicsWidget->property("text");
            if (text.isValid()) {
                mTraverseUtils->addTextInfo(objectInfo, text.toString(), graphicsWidget->font(), graphicsWidget->size().width());

            }
            QVariant plainText = graphicsWidget->property("plainText");
            if (plainText.isValid()) {
                mTraverseUtils->addTextInfo(objectInfo, plainText.toString(), graphicsWidget->font(), graphicsWidget->size().width());
            }
        }
    }
    else{
        //make sure that we are dealing with a widget
        if (object->isWidgetType()){
            QWidget* widget = qobject_cast<QWidget*>(object);
            objectInfo->addAttribute("objectType", TYPE_STANDARD_VIEW );

            addWidgetCoordinates(objectInfo, widget,command);
            mTraverseUtils->addFont(objectInfo, widget->font());
            //check is the widget a viewport to graphicsscene
            QWidget* parentWidget = widget->parentWidget();
            bool isViewPort = false;
            if(parentWidget && parentWidget->inherits("QGraphicsView")){
                QGraphicsView* view = qobject_cast<QGraphicsView*>(parentWidget);
                if(view->viewport() == widget){
                    isViewPort = true;
                }
            }
            //add transformation details
            QGraphicsView* graphicsView = qobject_cast<QGraphicsView*>(object);
            if(graphicsView){
                objectInfo->addBooleanAttribute("isTransformed", graphicsView->isTransformed());
                if(graphicsView->isTransformed()){
                    QTransform tr = graphicsView->transform();
                    objectInfo->addAttribute("transformM11",tr.m11());
                    objectInfo->addAttribute("transformM12",tr.m12());
                    objectInfo->addAttribute("transformM13",tr.m13());
                    objectInfo->addAttribute("transformM21",tr.m21());
                    objectInfo->addAttribute("transformM22",tr.m22());
                    objectInfo->addAttribute("transformM23",tr.m23());
                    objectInfo->addAttribute("transformM31",tr.m31());
                    objectInfo->addAttribute("transformM32",tr.m32());
                    objectInfo->addAttribute("transformM33",tr.m33());
                }
            }
            objectInfo->addBooleanAttribute("isViewPort", isViewPort);
// Add special window id attribute into qwidget atttributes
#if defined(Q_WS_X11)
            unsigned long wid = static_cast<unsigned long>(widget->effectiveWinId());
            objectInfo->addAttribute("xWindow", (int)wid); // can this fail due to precision?
#endif

        } else {
            if(object != qApp){
                objectInfo->addAttribute("objectType", embeddedApp? TYPE_WEB : TYPE_STANDARD_VIEW );
            }
        }

    }
}

void TasQtTraverse::addWidgetCoordinates(TasObject* objectInfo, QWidget* widget, TasCommand* command)
{
    objectInfo->addBooleanAttribute("isWindow", widget->isWindow());

    QGraphicsProxyWidget* proxy = TestabilityUtils::parentProxy(widget);
    if (proxy) {
        //TasLogger::logger()->debug("TasQtTraverse::addWidgetCoordinates got proxy");
        //print window coordinates

        QRectF sceneRect = proxy->sceneBoundingRect();
        QGraphicsView* view = TestabilityUtils::getViewForItem(proxy);
        if(!view->viewportTransform().isIdentity()){
            QTransform transform = view->viewportTransform();
            sceneRect = transform.mapRect(sceneRect);
        }
        QPoint point = sceneRect.topLeft().toPoint();

        //Print screen coordinates
        QPoint windowPoint = widget->mapTo(widget->window(),QPoint(0, 0));
        windowPoint += point;
        objectInfo->addAttribute("x", windowPoint.x());
        objectInfo->addAttribute("y", windowPoint.y());

        objectInfo->addAttribute("x_absolute", windowPoint.x());
        objectInfo->addAttribute("y_absolute", windowPoint.y());
    }
    else {
        QPoint screenPoint;
        if (command && command->parameter("x_parent_absolute") != "" &&
            command->parameter("y_parent_absolute") != "") {
            //TasLogger::logger()->debug("TasQtTraverse::addWidgetCoordinates moving point");
            QPoint p(command->parameter("x_parent_absolute").toInt(),
                     command->parameter("y_parent_absolute").toInt());
            screenPoint = widget->mapToGlobal(p);

            objectInfo->addAttribute("x_absolute", screenPoint.x());
            objectInfo->addAttribute("y_absolute", screenPoint.y());

        } else {
            //TasLogger::logger()->debug("TasQtTraverse::addWidgetCoordinates using regular coords");
            screenPoint = widget->mapToGlobal(QPoint(0, 0));
            objectInfo->addAttribute("x_absolute", screenPoint.x());
            objectInfo->addAttribute("y_absolute", screenPoint.y());
        }
         //print window coordinates

        QPoint windowPoint = widget->window()->mapFromGlobal(screenPoint);
        objectInfo->addAttribute("x", windowPoint.x());
        objectInfo->addAttribute("y", windowPoint.y());

    }
    // Explicitly add width and height (property added changes name)
    objectInfo->addAttribute("width", widget->width());
    objectInfo->addAttribute("height", widget->height());
}

<|endoftext|>


<commit_before>#pragma once
#include <stdio.h>
#include <cstdint>

using byte = uint8_t; static_assert(sizeof(byte) == 1);
using int8 = int8_t; static_assert(sizeof(int8) == 1);
using int16 = int16_t; static_assert(sizeof(int16) == 2);
using int32 = int32_t; static_assert(sizeof(int32) == 4);
using int64 = int64_t; static_assert(sizeof(int64) == 8);
using uint8 = uint8_t; static_assert(sizeof(byte) == 1);
using uint16 = uint16_t; static_assert(sizeof(uint16) == 2);
using uint32 = uint32_t; static_assert(sizeof(uint32) == 4);
using uint64 = uint64_t; static_assert(sizeof(uint64) == 8);

#ifndef DAR_MODULE_NAME
  #define DAR_MODULE_NAME ""
#endif

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

  #define logError(message, ...) \
  { \
    char stringBuffer[1024]; \
    _snprintf_s(stringBuffer, sizeof(stringBuffer), "[ERROR][" DAR_MODULE_NAME "] " message "\n", __VA_ARGS__); \
    OutputDebugStringA(stringBuffer); \
  }
  #define logWarning(message, ...) \
  { \
    char stringBuffer[1024]; \
    _snprintf_s(stringBuffer, sizeof(stringBuffer), "[WARN][" DAR_MODULE_NAME "] " message "\n", __VA_ARGS__); \
    OutputDebugStringA(stringBuffer); \
  }
  #define logInfo(message, ...) \
  { \
    char stringBuffer[1024]; \
    _snprintf_s(stringBuffer, sizeof(stringBuffer), "[INFO][" DAR_MODULE_NAME "] " message "\n", __VA_ARGS__); \
    OutputDebugStringA(stringBuffer); \
  }
#endif
#define logVariable(variable, format) logInfo(#variable " = " format, variable)

#define arrayLength(arr) (sizeof(arr) / sizeof(arr[0]))

#ifdef DAR_DEBUG
  #undef assert
  #define assert(condition) \
    if(!(condition)) { \
      logError("Assertion failed: %s", #condition); \
      *(int*)0 = 0; \
    }

  extern wchar_t _debugText[4096];
  extern int _debugTextLength;

  #define debugResetText() _debugTextLength = 0;

  void _debugStringImpl(const wchar_t* newStr, int newStrLength);
  #define debugText(...) \
  { \
    wchar_t newStr[256]; \
    int newStrLength = _snwprintf_s(newStr, _TRUNCATE, __VA_ARGS__); \
    if(newStrLength > 0) _debugStringImpl(newStr, newStrLength); \
  }
#else
  #undef assert
  #define assert(condition) ((void)0)
  #define debugText(...)
  #define debugResetText()
#endif<commit_msg>Added nativeToBigEndian function + some platform and compiler preprocessor defines.<commit_after>#pragma once

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

using byte = uint8_t; static_assert(sizeof(byte) == 1);
using int8 = int8_t; static_assert(sizeof(int8) == 1);
using int16 = int16_t; static_assert(sizeof(int16) == 2);
using int32 = int32_t; static_assert(sizeof(int32) == 4);
using int64 = int64_t; static_assert(sizeof(int64) == 8);
using uint8 = uint8_t; static_assert(sizeof(byte) == 1);
using uint16 = uint16_t; static_assert(sizeof(uint16) == 2);
using uint32 = uint32_t; static_assert(sizeof(uint32) == 4);
using uint64 = uint64_t; static_assert(sizeof(uint64) == 8);

#ifndef DAR_MODULE_NAME
  #define DAR_MODULE_NAME ""
#endif

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

  #define logError(message, ...) \
  { \
    char stringBuffer[1024]; \
    _snprintf_s(stringBuffer, sizeof(stringBuffer), "[ERROR][" DAR_MODULE_NAME "] " message "\n", __VA_ARGS__); \
    OutputDebugStringA(stringBuffer); \
  }
  #define logWarning(message, ...) \
  { \
    char stringBuffer[1024]; \
    _snprintf_s(stringBuffer, sizeof(stringBuffer), "[WARN][" DAR_MODULE_NAME "] " message "\n", __VA_ARGS__); \
    OutputDebugStringA(stringBuffer); \
  }
  #define logInfo(message, ...) \
  { \
    char stringBuffer[1024]; \
    _snprintf_s(stringBuffer, sizeof(stringBuffer), "[INFO][" DAR_MODULE_NAME "] " message "\n", __VA_ARGS__); \
    OutputDebugStringA(stringBuffer); \
  }
#endif
#define logVariable(variable, format) logInfo(#variable " = " format, variable)

#define arrayLength(arr) (sizeof(arr) / sizeof(arr[0]))

#ifdef DAR_DEBUG
  #undef assert
  #define assert(condition) \
    if(!(condition)) { \
      logError("Assertion failed: %s", #condition); \
      *(int*)0 = 0; \
    }

  extern wchar_t _debugText[4096];
  extern int _debugTextLength;

  #define debugResetText() _debugTextLength = 0;

  void _debugStringImpl(const wchar_t* newStr, int newStrLength);
  #define debugText(...) \
  { \
    wchar_t newStr[256]; \
    int newStrLength = _snwprintf_s(newStr, _TRUNCATE, __VA_ARGS__); \
    if(newStrLength > 0) _debugStringImpl(newStr, newStrLength); \
  }
#else
  #undef assert
  #define assert(condition) ((void)0)
  #define debugText(...)
  #define debugResetText()
#endif

#define PLATFORM_WINDOWS 1 // Only supported platform so far

#if PLATFORM_WINDOWS
  #define LITTLE_ENDIAN 1
  #define BIG_ENDIAN 0
#endif

#ifdef _MSC_VER
  #define COMPILER_MSVC 1
#else
  #define COMPILER_MSVC 0
#endif

inline uint16 nativeToBigEndian(uint16 value)
{
#if BIG_ENDIAN
    return value;
#elif COMPILER_MSVC
    return _byteswap_ushort(value);
#endif
}<|endoftext|>


<commit_before>#ifndef _WTF_ENGINE_HPP
#define _WTF_ENGINE_HPP

#include <cstdint>
#include "WTF_API.h"

namespace WTFDanmaku {

    class Controller;

    WTF_API enum Type : int {
        Scrolling = 1,
        Bottom = 4,
        Top = 5,
        Reverse = 6,
        Position = 7,
        Advanced = 8
    };

    class WTF_API WTFEngine {
    public:
        explicit WTFEngine();
        ~WTFEngine();
        void Initialize(void* hwnd);
        void LoadBilibiliFile(const char* filePath);
        void LoadBilibiliXml(const char* str);
        void AddDanmaku(Type type, time_t time, const wchar_t* comment, int fontSize, int fontColor, time_t timestamp = 0, int danmakuId = 0);
        void AddLiveDanmaku(Type type, time_t time, const wchar_t* comment, int fontSize, int fontColor, time_t timestamp = 0, int danmakuId = 0);
        void Start();
        void Pause();
        void Resume();
        void Stop();
        void SeekTo(time_t milliseconds);
        time_t GetCurrentPosition();
        bool IsRunning();
    private:
        WTFEngine(const WTFEngine&) = delete;
        WTFEngine& operator=(const WTFEngine&) = delete;
    private:
        Controller* mController;
    };

}

#endif // _WTF_ENGINE_HPP<commit_msg>WTFEngine.hpp: Fix a compile warning under MSVC 2015<commit_after>#ifndef _WTF_ENGINE_HPP
#define _WTF_ENGINE_HPP

#include <cstdint>
#include "WTF_API.h"

namespace WTFDanmaku {

    class Controller;

    enum Type : int {
        Scrolling = 1,
        Bottom = 4,
        Top = 5,
        Reverse = 6,
        Position = 7,
        Advanced = 8
    };

    class WTF_API WTFEngine {
    public:
        explicit WTFEngine();
        ~WTFEngine();
        void Initialize(void* hwnd);
        void LoadBilibiliFile(const char* filePath);
        void LoadBilibiliXml(const char* str);
        void AddDanmaku(Type type, time_t time, const wchar_t* comment, int fontSize, int fontColor, time_t timestamp = 0, int danmakuId = 0);
        void AddLiveDanmaku(Type type, time_t time, const wchar_t* comment, int fontSize, int fontColor, time_t timestamp = 0, int danmakuId = 0);
        void Start();
        void Pause();
        void Resume();
        void Stop();
        void SeekTo(time_t milliseconds);
        time_t GetCurrentPosition();
        bool IsRunning();
    private:
        WTFEngine(const WTFEngine&) = delete;
        WTFEngine& operator=(const WTFEngine&) = delete;
    private:
        Controller* mController;
    };

}

#endif // _WTF_ENGINE_HPP<|endoftext|>


<commit_before>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/

#ifndef REALM_UTIL_EMULATED_ROBUST_MUTEX
#define REALM_UTIL_EMULATED_ROBUST_MUTEX

// Enable this only on platforms where it might be needed
// currently APPLE.
#if REALM_PLATFORM_APPLE
#define REALM_ROBUST_MUTEX_EMULATION
#endif

#include <realm/util/features.h>
#include <realm/util/thread.hpp>
#include <realm/util/file.hpp>

namespace realm {
namespace util {

// fwd decl to support friend decl below
class PlatformSpecificCondVar;

/// Emulation of a Robust Mutex.
/// A Robust Mutex is an interprocess mutex which will automatically
/// release any locks held by a process when it crashes. Contrary to
/// Posix robust mutexes, this robust mutex is not capable of informing
/// participants that they have been granted a lock after a crash of
/// the process holding it (though it could be added if needed).

class EmulatedRobustMutex {
public:
    EmulatedRobustMutex();
    ~EmulatedRobustMutex() noexcept;

#ifdef REALM_ROBUST_MUTEX_EMULATION
    struct SharedPart { };
#else
    using SharedPart = RobustMutex;
#endif

    /// You need to bind the emulation to a SharedPart in shared/mmapped memory.
    /// The SharedPart is assumed to have been initialized (possibly by another process)
    /// elsewhere.
    void set_shared_part(SharedPart& shared_part, std::string path, std::string mutex_name);

    /// Lock the mutex. If the mutex is already locked, wait for it to be unlocked.
    void lock();

    /// Unlock the mutex
    void unlock();

    /// Attempt to check if the mutex is valid (only relevant if not emulating)
    bool is_valid() noexcept;

    static bool is_robust_on_this_platform()
    {
#ifdef REALM_ROBUST_MUTEX_EMULATION
        return true;  // we're faking it!
#else
        return RobustMutex::is_robust_on_this_platform();
#endif
    }
private:
#ifndef REALM_ROBUST_MUTEX_EMULATION
    SharedPart* m_shared_part = 0;
#else
    std::string m_filename;
    File m_file;
    Mutex m_local_mutex;
#endif
    friend class PlatformSpecificCondVar;
};

inline EmulatedRobustMutex::EmulatedRobustMutex()
{
}

inline EmulatedRobustMutex::~EmulatedRobustMutex() noexcept
{
#ifdef REALM_ROBUST_MUTEX_EMULATION
    m_local_mutex.lock();
    m_file.close();
    m_local_mutex.unlock();
#endif
}

inline void EmulatedRobustMutex::set_shared_part(SharedPart& shared_part,
                                                 std::string path,
                                                 std::string mutex_name)
{
#ifndef REALM_ROBUST_MUTEX_EMULATION
    m_shared_part = &shared_part;
    static_cast<void>(path);
    static_cast<void>(mutex_name);
#else
    static_cast<void>(shared_part);
    if (m_file.is_attached()) {
        m_file.close();
    }
    m_filename = path + "." + mutex_name + ".mx";
    m_local_mutex.lock();
    m_file.open(m_filename, File::mode_Write);
    m_local_mutex.unlock();
#endif
}

inline void EmulatedRobustMutex::lock()
{
#ifndef REALM_ROBUST_MUTEX_EMULATION
    REALM_ASSERT(m_shared_part);
    m_shared_part->lock([](){});
#else
    m_local_mutex.lock();
    m_file.lock_exclusive();
#endif
}

inline void EmulatedRobustMutex::unlock()
{
#ifndef REALM_ROBUST_MUTEX_EMULATION
    REALM_ASSERT(m_shared_part);
    m_shared_part->unlock();
#else
    m_file.unlock();
    m_local_mutex.unlock();
#endif
}

inline bool EmulatedRobustMutex::is_valid() noexcept
{
#ifndef REALM_ROBUST_MUTEX_EMULATION
    REALM_ASSERT(m_shared_part);
    return m_shared_part->is_valid();
#else
    return true;
#endif
}

} // namespace util
} // namespace realm

#endif // #ifndef REALM_UTIL_EMULATED_ROBUST_MUTEX
<commit_msg>fixed inconsistent use of ifdef/ifndef<commit_after>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/

#ifndef REALM_UTIL_EMULATED_ROBUST_MUTEX
#define REALM_UTIL_EMULATED_ROBUST_MUTEX

// Enable this only on platforms where it might be needed
// currently APPLE.
#if REALM_PLATFORM_APPLE
#define REALM_ROBUST_MUTEX_EMULATION
#endif

#include <realm/util/features.h>
#include <realm/util/thread.hpp>
#include <realm/util/file.hpp>

namespace realm {
namespace util {

// fwd decl to support friend decl below
class PlatformSpecificCondVar;

/// Emulation of a Robust Mutex.
/// A Robust Mutex is an interprocess mutex which will automatically
/// release any locks held by a process when it crashes. Contrary to
/// Posix robust mutexes, this robust mutex is not capable of informing
/// participants that they have been granted a lock after a crash of
/// the process holding it (though it could be added if needed).

class EmulatedRobustMutex {
public:
    EmulatedRobustMutex();
    ~EmulatedRobustMutex() noexcept;

#ifdef REALM_ROBUST_MUTEX_EMULATION
    struct SharedPart { };
#else
    using SharedPart = RobustMutex;
#endif

    /// You need to bind the emulation to a SharedPart in shared/mmapped memory.
    /// The SharedPart is assumed to have been initialized (possibly by another process)
    /// elsewhere.
    void set_shared_part(SharedPart& shared_part, std::string path, std::string mutex_name);

    /// Lock the mutex. If the mutex is already locked, wait for it to be unlocked.
    void lock();

    /// Unlock the mutex
    void unlock();

    /// Attempt to check if the mutex is valid (only relevant if not emulating)
    bool is_valid() noexcept;

    static bool is_robust_on_this_platform()
    {
#ifdef REALM_ROBUST_MUTEX_EMULATION
        return true;  // we're faking it!
#else
        return RobustMutex::is_robust_on_this_platform();
#endif
    }
private:
#ifdef REALM_ROBUST_MUTEX_EMULATION
    std::string m_filename;
    File m_file;
    Mutex m_local_mutex;
#else
    SharedPart* m_shared_part = 0;
#endif
    friend class PlatformSpecificCondVar;
};

inline EmulatedRobustMutex::EmulatedRobustMutex()
{
}

inline EmulatedRobustMutex::~EmulatedRobustMutex() noexcept
{
#ifdef REALM_ROBUST_MUTEX_EMULATION
    m_local_mutex.lock();
    m_file.close();
    m_local_mutex.unlock();
#endif
}

inline void EmulatedRobustMutex::set_shared_part(SharedPart& shared_part,
                                                 std::string path,
                                                 std::string mutex_name)
{
#ifdef REALM_ROBUST_MUTEX_EMULATION
    static_cast<void>(shared_part);
    if (m_file.is_attached()) {
        m_file.close();
    }
    m_filename = path + "." + mutex_name + ".mx";
    m_local_mutex.lock();
    m_file.open(m_filename, File::mode_Write);
    m_local_mutex.unlock();
#else
    m_shared_part = &shared_part;
    static_cast<void>(path);
    static_cast<void>(mutex_name);

#endif
}

inline void EmulatedRobustMutex::lock()
{
#ifdef REALM_ROBUST_MUTEX_EMULATION
    m_local_mutex.lock();
    m_file.lock_exclusive();
#else
    REALM_ASSERT(m_shared_part);
    m_shared_part->lock([](){});
#endif
}

inline void EmulatedRobustMutex::unlock()
{
#ifdef REALM_ROBUST_MUTEX_EMULATION
    m_file.unlock();
    m_local_mutex.unlock();
#else
    REALM_ASSERT(m_shared_part);
    m_shared_part->unlock();
#endif
}

inline bool EmulatedRobustMutex::is_valid() noexcept
{
#ifdef REALM_ROBUST_MUTEX_EMULATION
    return true;
#else
    REALM_ASSERT(m_shared_part);
    return m_shared_part->is_valid();
#endif
}

} // namespace util
} // namespace realm

#endif // #ifndef REALM_UTIL_EMULATED_ROBUST_MUTEX
<|endoftext|>


<commit_before>/*
 ***********************************************************************************************************************
 *
 *  Copyright (c) 2018-2020 Advanced Micro Devices, Inc. All Rights Reserved.
 *
 *  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.
 *
 **********************************************************************************************************************/
/**
***********************************************************************************************************************
* @file  PatchPrepareAbi.cpp
* @brief LLPC source file: contains declaration and implementation of class lgc::PatchPreparePipelineAbi.
***********************************************************************************************************************
*/
#include "Gfx6ConfigBuilder.h"
#include "Gfx9ConfigBuilder.h"
#include "ShaderMerger.h"
#include "lgc/patch/Patch.h"
#include "lgc/state/PalMetadata.h"
#include "lgc/state/PipelineShaders.h"
#include "lgc/state/PipelineState.h"
#include "lgc/state/TargetInfo.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"

#define DEBUG_TYPE "lgc-patch-prepare-pipeline-abi"

using namespace llvm;
using namespace lgc;

namespace lgc {

// =====================================================================================================================
// Pass to prepare the pipeline ABI
class PatchPreparePipelineAbi final : public Patch {
public:
  static char ID;
  PatchPreparePipelineAbi(bool onlySetCallingConvs = false) : Patch(ID), MOnlySetCallingConvs(onlySetCallingConvs) {}

  bool runOnModule(Module &module) override;

  void getAnalysisUsage(AnalysisUsage &analysisUsage) const override {
    analysisUsage.addRequired<PipelineStateWrapper>();
    analysisUsage.addRequired<PipelineShaders>();
  }

private:
  PatchPreparePipelineAbi(const PatchPreparePipelineAbi &) = delete;
  PatchPreparePipelineAbi &operator=(const PatchPreparePipelineAbi &) = delete;

  void setCallingConvs(Module &module);

  void mergeShaderAndSetCallingConvs(Module &module);

  void setCallingConv(ShaderStage stage, CallingConv::ID callingConv);

  void setAbiEntryNames(Module &module);

  void addAbiMetadata(Module &module);

  PipelineState *m_pipelineState;     // Pipeline state
  PipelineShaders *m_pipelineShaders; // API shaders in the pipeline

  bool m_hasVs;  // Whether the pipeline has vertex shader
  bool m_hasTcs; // Whether the pipeline has tessellation control shader
  bool m_hasTes; // Whether the pipeline has tessellation evaluation shader
  bool m_hasGs;  // Whether the pipeline has geometry shader

  GfxIpVersion m_gfxIp; // Graphics IP version info

  const bool MOnlySetCallingConvs; // Whether to only set the calling conventions
};

char PatchPreparePipelineAbi::ID = 0;

} // namespace lgc

// =====================================================================================================================
// Create pass to prepare the pipeline ABI
//
// @param onlySetCallingConvs : Should we only set the calling conventions, or do the full prepare.
ModulePass *lgc::createPatchPreparePipelineAbi(bool onlySetCallingConvs) {
  return new PatchPreparePipelineAbi(onlySetCallingConvs);
}

// =====================================================================================================================
// Run the pass on the specified LLVM module.
//
// @param [in,out] module : LLVM module to be run on
bool PatchPreparePipelineAbi::runOnModule(Module &module) {
  LLVM_DEBUG(dbgs() << "Run the pass Patch-Prepare-Pipeline-Abi\n");

  Patch::init(&module);

  m_pipelineState = getAnalysis<PipelineStateWrapper>().getPipelineState(&module);
  m_pipelineShaders = &getAnalysis<PipelineShaders>();

  m_hasVs = m_pipelineState->hasShaderStage(ShaderStageVertex);
  m_hasTcs = m_pipelineState->hasShaderStage(ShaderStageTessControl);
  m_hasTes = m_pipelineState->hasShaderStage(ShaderStageTessEval);
  m_hasGs = m_pipelineState->hasShaderStage(ShaderStageGeometry);

  m_gfxIp = m_pipelineState->getTargetInfo().getGfxIpVersion();

  // If we've only to set the calling conventions, do that now.
  if (MOnlySetCallingConvs)
    setCallingConvs(module);
  else {
    if (m_gfxIp.major >= 9)
      mergeShaderAndSetCallingConvs(module);

    setAbiEntryNames(module);

    addAbiMetadata(module);

    // TODO Shader compilation: Only do this if doing a whole-pipeline compilation
    m_pipelineState->getPalMetadata()->finalizePipeline();
  }

  return true; // Modified the module.
}

// =====================================================================================================================
// Set calling convention for the entry-point of each shader (pre-GFX9)
//
// @param module : LLVM module
void PatchPreparePipelineAbi::setCallingConvs(Module &module) {
  const bool hasTs = (m_hasTcs || m_hasTes);

  // NOTE: For each entry-point, set the calling convention appropriate to the hardware shader stage. The action here
  // depends on the pipeline type.
  setCallingConv(ShaderStageCompute, CallingConv::AMDGPU_CS);
  setCallingConv(ShaderStageFragment, CallingConv::AMDGPU_PS);

  if (hasTs && m_hasGs) {
    // TS-GS pipeline
    setCallingConv(ShaderStageVertex, CallingConv::AMDGPU_LS);
    setCallingConv(ShaderStageTessControl, CallingConv::AMDGPU_HS);
    setCallingConv(ShaderStageTessEval, CallingConv::AMDGPU_ES);
    setCallingConv(ShaderStageGeometry, CallingConv::AMDGPU_GS);
    setCallingConv(ShaderStageCopyShader, CallingConv::AMDGPU_VS);
  } else if (hasTs) {
    // TS-only pipeline
    setCallingConv(ShaderStageVertex, CallingConv::AMDGPU_LS);
    setCallingConv(ShaderStageTessControl, CallingConv::AMDGPU_HS);
    setCallingConv(ShaderStageTessEval, CallingConv::AMDGPU_VS);
  } else if (m_hasGs) {
    // GS-only pipeline
    setCallingConv(ShaderStageVertex, CallingConv::AMDGPU_ES);
    setCallingConv(ShaderStageGeometry, CallingConv::AMDGPU_GS);
    setCallingConv(ShaderStageCopyShader, CallingConv::AMDGPU_VS);
  } else if (m_hasVs) {
    // VS-FS pipeine
    setCallingConv(ShaderStageVertex, CallingConv::AMDGPU_VS);
  }
}

// =====================================================================================================================
// Merge shaders and set calling convention for the entry-point of each each shader (GFX9+)
//
// @param module : LLVM module
void PatchPreparePipelineAbi::mergeShaderAndSetCallingConvs(Module &module) {
  assert(m_gfxIp.major >= 9);

  const bool hasTs = (m_hasTcs || m_hasTes);

  // NOTE: For each entry-point, set the calling convention appropriate to the hardware shader stage. The action here
  // depends on the pipeline type, and, for GFX9+, may involve merging shaders.
  setCallingConv(ShaderStageCompute, CallingConv::AMDGPU_CS);
  setCallingConv(ShaderStageFragment, CallingConv::AMDGPU_PS);

  if (m_pipelineState->isGraphics()) {
    ShaderMerger shaderMerger(m_pipelineState, m_pipelineShaders);
    const bool enableNgg = m_pipelineState->getNggControl()->enableNgg;

    if (hasTs && m_hasGs) {
      // TS-GS pipeline
      if (m_hasTcs) {
        auto lsEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageVertex);
        auto hsEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageTessControl);

        if (hsEntryPoint) {
          auto lsHsEntryPoint = shaderMerger.generateLsHsEntryPoint(lsEntryPoint, hsEntryPoint);
          lsHsEntryPoint->setCallingConv(CallingConv::AMDGPU_HS);
        }
      }

      auto esEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageTessEval);
      auto gsEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageGeometry);

      if (enableNgg) {
        if (gsEntryPoint) {
          auto copyShaderEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageCopyShader);
          auto primShaderEntryPoint = shaderMerger.buildPrimShader(esEntryPoint, gsEntryPoint, copyShaderEntryPoint);
          primShaderEntryPoint->setCallingConv(CallingConv::AMDGPU_GS);
        }
      } else {
        if (gsEntryPoint) {
          auto esGsEntryPoint = shaderMerger.generateEsGsEntryPoint(esEntryPoint, gsEntryPoint);
          esGsEntryPoint->setCallingConv(CallingConv::AMDGPU_GS);
        }

        setCallingConv(ShaderStageCopyShader, CallingConv::AMDGPU_VS);
      }
    } else if (hasTs) {
      // TS-only pipeline
      if (m_hasTcs) {
        auto lsEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageVertex);
        auto hsEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageTessControl);

        if (hsEntryPoint) {
          auto lsHsEntryPoint = shaderMerger.generateLsHsEntryPoint(lsEntryPoint, hsEntryPoint);
          lsHsEntryPoint->setCallingConv(CallingConv::AMDGPU_HS);
        }
      }

      if (enableNgg) {
        // If NGG is enabled, ES-GS merged shader should be present even if GS is absent
        auto esEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageTessEval);

        if (esEntryPoint) {
          auto primShaderEntryPoint = shaderMerger.buildPrimShader(esEntryPoint, nullptr, nullptr);
          primShaderEntryPoint->setCallingConv(CallingConv::AMDGPU_GS);
        }
      } else
        setCallingConv(ShaderStageTessEval, CallingConv::AMDGPU_VS);
    } else if (m_hasGs) {
      // GS-only pipeline
      auto esEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageVertex);
      auto gsEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageGeometry);

      if (enableNgg) {
        if (gsEntryPoint) {
          auto copyShaderEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageCopyShader);
          auto primShaderEntryPoint = shaderMerger.buildPrimShader(esEntryPoint, gsEntryPoint, copyShaderEntryPoint);
          primShaderEntryPoint->setCallingConv(CallingConv::AMDGPU_GS);
        }
      } else {
        if (gsEntryPoint) {
          auto esGsEntryPoint = shaderMerger.generateEsGsEntryPoint(esEntryPoint, gsEntryPoint);
          esGsEntryPoint->setCallingConv(CallingConv::AMDGPU_GS);
        }

        setCallingConv(ShaderStageCopyShader, CallingConv::AMDGPU_VS);
      }
    } else if (m_hasVs) {
      // VS_FS pipeline
      if (enableNgg) {
        // If NGG is enabled, ES-GS merged shader should be present even if GS is absent
        auto esEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageVertex);
        if (esEntryPoint) {
          auto primShaderEntryPoint = shaderMerger.buildPrimShader(esEntryPoint, nullptr, nullptr);
          primShaderEntryPoint->setCallingConv(CallingConv::AMDGPU_GS);
        }
      } else
        setCallingConv(ShaderStageVertex, CallingConv::AMDGPU_VS);
    }
  }
}

// =====================================================================================================================
// Set calling convention on a particular API shader stage, if that stage has a shader
//
// @param shaderStage : Shader stage
// @param callingConv : Calling convention to set it to
void PatchPreparePipelineAbi::setCallingConv(ShaderStage shaderStage, CallingConv::ID callingConv) {
  auto entryPoint = m_pipelineShaders->getEntryPoint(shaderStage);
  if (entryPoint)
    entryPoint->setCallingConv(callingConv);
}

// =====================================================================================================================
// Set ABI-specified entrypoint name for each shader
//
// @param module : LLVM module
void PatchPreparePipelineAbi::setAbiEntryNames(Module &module) {
  for (auto &func : module) {
    if (!func.empty()) {
      auto callingConv = func.getCallingConv();
      const char *entryName = nullptr;

      switch (callingConv) {
      case CallingConv::AMDGPU_CS:
        entryName = Util::Abi::AmdGpuCsEntryName;
        break;
      case CallingConv::AMDGPU_PS:
        entryName = Util::Abi::AmdGpuPsEntryName;
        break;
      case CallingConv::AMDGPU_VS:
        entryName = Util::Abi::AmdGpuVsEntryName;
        break;
      case CallingConv::AMDGPU_GS:
        entryName = Util::Abi::AmdGpuGsEntryName;
        break;
      case CallingConv::AMDGPU_ES:
        entryName = Util::Abi::AmdGpuEsEntryName;
        break;
      case CallingConv::AMDGPU_HS:
        entryName = Util::Abi::AmdGpuHsEntryName;
        break;
      case CallingConv::AMDGPU_LS:
        entryName = Util::Abi::AmdGpuLsEntryName;
        break;
      default:
        continue;
      }
      func.setName(entryName);
    }
  }
}

// =====================================================================================================================
// Add ABI metadata
//
// @param module : LLVM module
void PatchPreparePipelineAbi::addAbiMetadata(Module &module) {
  if (m_gfxIp.major <= 8) {
    Gfx6::ConfigBuilder configBuilder(&module, m_pipelineState);
    configBuilder.buildPalMetadata();
  } else {
    Gfx9::ConfigBuilder configBuilder(&module, m_pipelineState);
    configBuilder.buildPalMetadata();
  }
}

// =====================================================================================================================
// Initializes the pass
INITIALIZE_PASS(PatchPreparePipelineAbi, DEBUG_TYPE, "Patch LLVM for preparing pipeline ABI", false, false)
<commit_msg>Force read-only data into .text in full pipeline compile<commit_after>/*
 ***********************************************************************************************************************
 *
 *  Copyright (c) 2018-2020 Advanced Micro Devices, Inc. All Rights Reserved.
 *
 *  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.
 *
 **********************************************************************************************************************/
/**
***********************************************************************************************************************
* @file  PatchPrepareAbi.cpp
* @brief LLPC source file: contains declaration and implementation of class lgc::PatchPreparePipelineAbi.
***********************************************************************************************************************
*/
#include "Gfx6ConfigBuilder.h"
#include "Gfx9ConfigBuilder.h"
#include "ShaderMerger.h"
#include "lgc/patch/Patch.h"
#include "lgc/state/PalMetadata.h"
#include "lgc/state/PipelineShaders.h"
#include "lgc/state/PipelineState.h"
#include "lgc/state/TargetInfo.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"

#define DEBUG_TYPE "lgc-patch-prepare-pipeline-abi"

using namespace llvm;
using namespace lgc;

namespace lgc {

// =====================================================================================================================
// Pass to prepare the pipeline ABI
class PatchPreparePipelineAbi final : public Patch {
public:
  static char ID;
  PatchPreparePipelineAbi(bool onlySetCallingConvs = false) : Patch(ID), MOnlySetCallingConvs(onlySetCallingConvs) {}

  bool runOnModule(Module &module) override;

  void getAnalysisUsage(AnalysisUsage &analysisUsage) const override {
    analysisUsage.addRequired<PipelineStateWrapper>();
    analysisUsage.addRequired<PipelineShaders>();
  }

private:
  PatchPreparePipelineAbi(const PatchPreparePipelineAbi &) = delete;
  PatchPreparePipelineAbi &operator=(const PatchPreparePipelineAbi &) = delete;

  void setCallingConvs(Module &module);

  void mergeShaderAndSetCallingConvs(Module &module);

  void setCallingConv(ShaderStage stage, CallingConv::ID callingConv);

  void setAbiEntryNames(Module &module);

  void addAbiMetadata(Module &module);

  void setConstantGlobalSection(Module &module);

  PipelineState *m_pipelineState;     // Pipeline state
  PipelineShaders *m_pipelineShaders; // API shaders in the pipeline

  bool m_hasVs;  // Whether the pipeline has vertex shader
  bool m_hasTcs; // Whether the pipeline has tessellation control shader
  bool m_hasTes; // Whether the pipeline has tessellation evaluation shader
  bool m_hasGs;  // Whether the pipeline has geometry shader

  GfxIpVersion m_gfxIp; // Graphics IP version info

  const bool MOnlySetCallingConvs; // Whether to only set the calling conventions
};

char PatchPreparePipelineAbi::ID = 0;

} // namespace lgc

// =====================================================================================================================
// Create pass to prepare the pipeline ABI
//
// @param onlySetCallingConvs : Should we only set the calling conventions, or do the full prepare.
ModulePass *lgc::createPatchPreparePipelineAbi(bool onlySetCallingConvs) {
  return new PatchPreparePipelineAbi(onlySetCallingConvs);
}

// =====================================================================================================================
// Run the pass on the specified LLVM module.
//
// @param [in,out] module : LLVM module to be run on
bool PatchPreparePipelineAbi::runOnModule(Module &module) {
  LLVM_DEBUG(dbgs() << "Run the pass Patch-Prepare-Pipeline-Abi\n");

  Patch::init(&module);

  m_pipelineState = getAnalysis<PipelineStateWrapper>().getPipelineState(&module);
  m_pipelineShaders = &getAnalysis<PipelineShaders>();

  m_hasVs = m_pipelineState->hasShaderStage(ShaderStageVertex);
  m_hasTcs = m_pipelineState->hasShaderStage(ShaderStageTessControl);
  m_hasTes = m_pipelineState->hasShaderStage(ShaderStageTessEval);
  m_hasGs = m_pipelineState->hasShaderStage(ShaderStageGeometry);

  m_gfxIp = m_pipelineState->getTargetInfo().getGfxIpVersion();

  // If we've only to set the calling conventions, do that now.
  if (MOnlySetCallingConvs)
    setCallingConvs(module);
  else {
    if (m_gfxIp.major >= 9)
      mergeShaderAndSetCallingConvs(module);

    setAbiEntryNames(module);

    addAbiMetadata(module);

    setConstantGlobalSection(module);

    // TODO Shader compilation: Only do this if doing a whole-pipeline compilation
    m_pipelineState->getPalMetadata()->finalizePipeline();
  }

  return true; // Modified the module.
}

// =====================================================================================================================
// Set calling convention for the entry-point of each shader (pre-GFX9)
//
// @param module : LLVM module
void PatchPreparePipelineAbi::setCallingConvs(Module &module) {
  const bool hasTs = (m_hasTcs || m_hasTes);

  // NOTE: For each entry-point, set the calling convention appropriate to the hardware shader stage. The action here
  // depends on the pipeline type.
  setCallingConv(ShaderStageCompute, CallingConv::AMDGPU_CS);
  setCallingConv(ShaderStageFragment, CallingConv::AMDGPU_PS);

  if (hasTs && m_hasGs) {
    // TS-GS pipeline
    setCallingConv(ShaderStageVertex, CallingConv::AMDGPU_LS);
    setCallingConv(ShaderStageTessControl, CallingConv::AMDGPU_HS);
    setCallingConv(ShaderStageTessEval, CallingConv::AMDGPU_ES);
    setCallingConv(ShaderStageGeometry, CallingConv::AMDGPU_GS);
    setCallingConv(ShaderStageCopyShader, CallingConv::AMDGPU_VS);
  } else if (hasTs) {
    // TS-only pipeline
    setCallingConv(ShaderStageVertex, CallingConv::AMDGPU_LS);
    setCallingConv(ShaderStageTessControl, CallingConv::AMDGPU_HS);
    setCallingConv(ShaderStageTessEval, CallingConv::AMDGPU_VS);
  } else if (m_hasGs) {
    // GS-only pipeline
    setCallingConv(ShaderStageVertex, CallingConv::AMDGPU_ES);
    setCallingConv(ShaderStageGeometry, CallingConv::AMDGPU_GS);
    setCallingConv(ShaderStageCopyShader, CallingConv::AMDGPU_VS);
  } else if (m_hasVs) {
    // VS-FS pipeine
    setCallingConv(ShaderStageVertex, CallingConv::AMDGPU_VS);
  }
}

// =====================================================================================================================
// Merge shaders and set calling convention for the entry-point of each each shader (GFX9+)
//
// @param module : LLVM module
void PatchPreparePipelineAbi::mergeShaderAndSetCallingConvs(Module &module) {
  assert(m_gfxIp.major >= 9);

  const bool hasTs = (m_hasTcs || m_hasTes);

  // NOTE: For each entry-point, set the calling convention appropriate to the hardware shader stage. The action here
  // depends on the pipeline type, and, for GFX9+, may involve merging shaders.
  setCallingConv(ShaderStageCompute, CallingConv::AMDGPU_CS);
  setCallingConv(ShaderStageFragment, CallingConv::AMDGPU_PS);

  if (m_pipelineState->isGraphics()) {
    ShaderMerger shaderMerger(m_pipelineState, m_pipelineShaders);
    const bool enableNgg = m_pipelineState->getNggControl()->enableNgg;

    if (hasTs && m_hasGs) {
      // TS-GS pipeline
      if (m_hasTcs) {
        auto lsEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageVertex);
        auto hsEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageTessControl);

        if (hsEntryPoint) {
          auto lsHsEntryPoint = shaderMerger.generateLsHsEntryPoint(lsEntryPoint, hsEntryPoint);
          lsHsEntryPoint->setCallingConv(CallingConv::AMDGPU_HS);
        }
      }

      auto esEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageTessEval);
      auto gsEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageGeometry);

      if (enableNgg) {
        if (gsEntryPoint) {
          auto copyShaderEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageCopyShader);
          auto primShaderEntryPoint = shaderMerger.buildPrimShader(esEntryPoint, gsEntryPoint, copyShaderEntryPoint);
          primShaderEntryPoint->setCallingConv(CallingConv::AMDGPU_GS);
        }
      } else {
        if (gsEntryPoint) {
          auto esGsEntryPoint = shaderMerger.generateEsGsEntryPoint(esEntryPoint, gsEntryPoint);
          esGsEntryPoint->setCallingConv(CallingConv::AMDGPU_GS);
        }

        setCallingConv(ShaderStageCopyShader, CallingConv::AMDGPU_VS);
      }
    } else if (hasTs) {
      // TS-only pipeline
      if (m_hasTcs) {
        auto lsEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageVertex);
        auto hsEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageTessControl);

        if (hsEntryPoint) {
          auto lsHsEntryPoint = shaderMerger.generateLsHsEntryPoint(lsEntryPoint, hsEntryPoint);
          lsHsEntryPoint->setCallingConv(CallingConv::AMDGPU_HS);
        }
      }

      if (enableNgg) {
        // If NGG is enabled, ES-GS merged shader should be present even if GS is absent
        auto esEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageTessEval);

        if (esEntryPoint) {
          auto primShaderEntryPoint = shaderMerger.buildPrimShader(esEntryPoint, nullptr, nullptr);
          primShaderEntryPoint->setCallingConv(CallingConv::AMDGPU_GS);
        }
      } else
        setCallingConv(ShaderStageTessEval, CallingConv::AMDGPU_VS);
    } else if (m_hasGs) {
      // GS-only pipeline
      auto esEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageVertex);
      auto gsEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageGeometry);

      if (enableNgg) {
        if (gsEntryPoint) {
          auto copyShaderEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageCopyShader);
          auto primShaderEntryPoint = shaderMerger.buildPrimShader(esEntryPoint, gsEntryPoint, copyShaderEntryPoint);
          primShaderEntryPoint->setCallingConv(CallingConv::AMDGPU_GS);
        }
      } else {
        if (gsEntryPoint) {
          auto esGsEntryPoint = shaderMerger.generateEsGsEntryPoint(esEntryPoint, gsEntryPoint);
          esGsEntryPoint->setCallingConv(CallingConv::AMDGPU_GS);
        }

        setCallingConv(ShaderStageCopyShader, CallingConv::AMDGPU_VS);
      }
    } else if (m_hasVs) {
      // VS_FS pipeline
      if (enableNgg) {
        // If NGG is enabled, ES-GS merged shader should be present even if GS is absent
        auto esEntryPoint = m_pipelineShaders->getEntryPoint(ShaderStageVertex);
        if (esEntryPoint) {
          auto primShaderEntryPoint = shaderMerger.buildPrimShader(esEntryPoint, nullptr, nullptr);
          primShaderEntryPoint->setCallingConv(CallingConv::AMDGPU_GS);
        }
      } else
        setCallingConv(ShaderStageVertex, CallingConv::AMDGPU_VS);
    }
  }
}

// =====================================================================================================================
// Set calling convention on a particular API shader stage, if that stage has a shader
//
// @param shaderStage : Shader stage
// @param callingConv : Calling convention to set it to
void PatchPreparePipelineAbi::setCallingConv(ShaderStage shaderStage, CallingConv::ID callingConv) {
  auto entryPoint = m_pipelineShaders->getEntryPoint(shaderStage);
  if (entryPoint)
    entryPoint->setCallingConv(callingConv);
}

// =====================================================================================================================
// Set ABI-specified entrypoint name for each shader
//
// @param module : LLVM module
void PatchPreparePipelineAbi::setAbiEntryNames(Module &module) {
  for (auto &func : module) {
    if (!func.empty()) {
      auto callingConv = func.getCallingConv();
      const char *entryName = nullptr;

      switch (callingConv) {
      case CallingConv::AMDGPU_CS:
        entryName = Util::Abi::AmdGpuCsEntryName;
        break;
      case CallingConv::AMDGPU_PS:
        entryName = Util::Abi::AmdGpuPsEntryName;
        break;
      case CallingConv::AMDGPU_VS:
        entryName = Util::Abi::AmdGpuVsEntryName;
        break;
      case CallingConv::AMDGPU_GS:
        entryName = Util::Abi::AmdGpuGsEntryName;
        break;
      case CallingConv::AMDGPU_ES:
        entryName = Util::Abi::AmdGpuEsEntryName;
        break;
      case CallingConv::AMDGPU_HS:
        entryName = Util::Abi::AmdGpuHsEntryName;
        break;
      case CallingConv::AMDGPU_LS:
        entryName = Util::Abi::AmdGpuLsEntryName;
        break;
      default:
        continue;
      }
      func.setName(entryName);
    }
  }
}

// =====================================================================================================================
// Add ABI metadata
//
// @param module : LLVM module
void PatchPreparePipelineAbi::addAbiMetadata(Module &module) {
  if (m_gfxIp.major <= 8) {
    Gfx6::ConfigBuilder configBuilder(&module, m_pipelineState);
    configBuilder.buildPalMetadata();
  } else {
    Gfx9::ConfigBuilder configBuilder(&module, m_pipelineState);
    configBuilder.buildPalMetadata();
  }
}

// =====================================================================================================================
// Set section name on each read-only global variable. For full pipeline compilation, we explicitly set the section
// name to ".text", as the PAL pipeline ABI requires constant data to be in the same section as the code. For
// shader/half-pipeline compilation, we leave it as default, which (after an LLVM change) puts the constant data
// into the .rodata section.
void PatchPreparePipelineAbi::setConstantGlobalSection(Module &module) {
  if (m_pipelineState->isUnlinked())
    return;
  for (GlobalVariable &global : module.globals()) {
    if (global.getAddressSpace() == ADDR_SPACE_CONST)
      global.setSection(".text");
  }
}

// =====================================================================================================================
// Initializes the pass
INITIALIZE_PASS(PatchPreparePipelineAbi, DEBUG_TYPE, "Patch LLVM for preparing pipeline ABI", false, false)
<|endoftext|>


<commit_before>#include "asset_compiler.h"
#include "bx/error.h"
#include "bx/process.h"
#include "bx/string.h"
#include "core/filesystem/filesystem.h"
#include "core/graphics/graphics.h"
#include "core/logging/logging.h"
#include "core/serialization/binary_archive.h"
#include "core/serialization/serialization.h"
#include "core/serialization/types/unordered_map.hpp"
#include "core/serialization/types/vector.hpp"
#include "core/string_utils/string_utils.h"
#include "core/uuid/uuid.hpp"
#include "mesh_importer.h"
#include "runtime/assets/asset_extensions.h"
#include "runtime/meta/animation/animation.hpp"
#include "runtime/meta/rendering/mesh.hpp"
#include "runtime/rendering/mesh.h"
#include "runtime/rendering/shader.h"
#include "runtime/rendering/texture.h"
#include <array>
#include <fstream>

class material;
struct prefab;
struct scene;

namespace asset_compiler
{
std::string escape_str(const std::string& str)
{
	return "\"" + str + "\"";
}

bool run_compile_process(const std::string& process, const std::vector<std::string>& args_array,
						 std::string& err)
{

	std::string args;
	size_t i = 0;
	for(const auto& arg : args_array)
	{
		if(arg.front() == '-')
		{
			args += arg;
		}
		else
		{
			args += escape_str(arg);
		}

		if(i++ != args_array.size() - 1)
			args += " ";
	}

	bx::Error error;
	bx::ProcessReader process_reader;

	auto executable_dir = fs::resolve_protocol("binary:/");
	auto process_full = executable_dir / process;

	process_reader.open((process_full.string() + " " + args).c_str(), "", &error);

	if(!error.isOk())
	{
		err = std::string(error.getMessage().getPtr());
		return false;
	}
	else
	{
		char buffer[2048];
		process_reader.read(buffer, sizeof(buffer), &error);

		process_reader.close();
		int32_t result = process_reader.getExitCode();

		if(0 != result)
		{
			err = std::string(error.getMessage().getPtr());
			return false;
		}

		return true;
	}
}

template <>
void compile<prefab>(const fs::path&)
{
}

template <>
void compile<scene>(const fs::path&)
{
}

template <>
void compile<material>(const fs::path&)
{
}

template <>
void compile<shader>(const fs::path& absolute_key)
{
	fs::path output = absolute_key.string() + extensions::get_compiled_format<shader>();
	std::string str_input = absolute_key.string();
	std::string file = absolute_key.stem().string();
	fs::path dir = absolute_key.parent_path();

	fs::error_code err;
	fs::path temp = fs::temp_directory_path(err);
	temp /= uuids::random_uuid(str_input).to_string() + ".buildtemp";

	std::string str_output = temp.string();
	fs::path include = fs::resolve_protocol("shader_include:/");
	std::string str_include = include.string();
	fs::path varying = dir / (file + ".io");
	std::string str_varying = varying.string();

	std::string str_platform;
	std::string str_profile;
	std::string str_type;

	bool vs = string_utils::begins_with(file, "vs_");
	bool fs = string_utils::begins_with(file, "fs_");
	bool cs = string_utils::begins_with(file, "cs_");

	auto renderer = gfx::getRendererType();
	if(renderer == gfx::RendererType::Direct3D11 || renderer == gfx::RendererType::Direct3D12)
	{
		str_platform = "windows";

		if(vs)
			str_profile = "vs_4_0";
		else if(fs)
			str_profile = "ps_4_0";
		else if(cs)
			str_profile = "cs_5_0";
	}
	else if(renderer == gfx::RendererType::OpenGL)
	{
		str_platform = "linux";

		if(vs || fs)
			str_profile = "120";
		else if(cs)
			str_profile = "430";
	}
	else if(renderer == gfx::RendererType::Metal)
	{
		str_platform = "osx";
		str_profile = "metal";
	}

	if(vs)
		str_type = "vertex";
	else if(fs)
		str_type = "fragment";
	else if(cs)
		str_type = "compute";
	else
		str_type = "unknown";

	const std::vector<std::string> args_array = {
		"-f",		  str_input.c_str(),	"-o",			str_output.c_str(),
		"-i",		  str_include.c_str(),  "--varyingdef", str_varying.c_str(),
		"--platform", str_platform.c_str(), "-p",			str_profile.c_str(),
		"--type",	 str_type.c_str(),		"-O",			"3",
	};

	std::string error;

	{
		std::ofstream output_file(str_output);
	}

	if(!run_compile_process("shaderc", args_array, error))
	{
		APPLOG_ERROR("Failed compilation of {0} with error: {1}", str_input, error);
	}
	else
	{
		APPLOG_INFO("Successful compilation of {0}", str_input);
		fs::copy_file(temp, output, fs::copy_option::overwrite_if_exists, err);
	}
	fs::remove(temp, err);
}

template <>
void compile<texture>(const fs::path& absolute_key)
{
	fs::path output = absolute_key.string() + extensions::get_compiled_format<texture>();
	std::string str_input = absolute_key.string();

	fs::error_code err;
	fs::path temp = fs::temp_directory_path(err);
    temp /= uuids::random_uuid(str_input).to_string() + ".buildtemp";

	std::string str_output = temp.string();

	const std::vector<std::string> args_array = {
		"-f", str_input.c_str(), "-o", str_output.c_str(), "--as", "ktx", "-m", "-t", "BGRA8",
	};

	std::string error;

	{
		std::ofstream output_file(str_output);
	}

	if(!run_compile_process("texturec", args_array, error))
	{
		APPLOG_ERROR("Failed compilation of {0} with error: {1}", str_input, error);
	}
	else
	{
		APPLOG_INFO("Successful compilation of {0}", str_input);
		fs::copy_file(temp, output, fs::copy_option::overwrite_if_exists, err);
	}
	fs::remove(temp, err);
}

template <>
void compile<mesh>(const fs::path& absolute_key)
{
	fs::path output = absolute_key.string() + extensions::get_compiled_format<mesh>();
	std::string str_input = absolute_key.string();

	fs::error_code err;
	fs::path temp = fs::temp_directory_path(err);
    temp /= uuids::random_uuid(str_input).to_string() + ".buildtemp";

	mesh::load_data data;
	std::vector<animation> animations;
	if(!importer::load_mesh_data_from_file(str_input, data, animations))
	{
		APPLOG_ERROR("Failed compilation of {0}", str_input);
		return;
	}

	if(data.vertex_data.empty() == false)
	{
		{
			std::ofstream soutput(temp.string(), std::ios::out | std::ios::binary);
			cereal::oarchive_binary_t ar(soutput);
			try_save(ar, cereal::make_nvp("mesh", data));
		}
		fs::copy_file(temp, output, fs::copy_option::overwrite_if_exists, err);
		fs::remove(temp, err);

		APPLOG_INFO("Successful compilation of {0}", str_input);
		{
			fs::path file = absolute_key.stem();
			fs::path dir = absolute_key.parent_path();

			for(const auto& animation : animations)
			{
				temp = fs::temp_directory_path(err);
				temp.append(uuids::random_uuid(str_input).to_string() + ".buildtemp");
				{
					std::ofstream soutput(temp.string(), std::ios::out | std::ios::binary);
					cereal::oarchive_binary_t ar(soutput);
					try_save(ar, cereal::make_nvp("animation", animation));
				}
				output = (dir / file).string() + "_" + animation.name + extensions::animation;

				fs::copy_file(temp, output, fs::copy_option::overwrite_if_exists, err);
				fs::remove(temp, err);
			}
		}
	}
}
}
<commit_msg>fixed popen args formatting..<commit_after>#include "asset_compiler.h"
#include "bx/error.h"
#include "bx/process.h"
#include "bx/string.h"
#include "core/filesystem/filesystem.h"
#include "core/graphics/graphics.h"
#include "core/logging/logging.h"
#include "core/serialization/binary_archive.h"
#include "core/serialization/serialization.h"
#include "core/serialization/types/unordered_map.hpp"
#include "core/serialization/types/vector.hpp"
#include "core/string_utils/string_utils.h"
#include "core/uuid/uuid.hpp"
#include "mesh_importer.h"
#include "runtime/assets/asset_extensions.h"
#include "runtime/meta/animation/animation.hpp"
#include "runtime/meta/rendering/mesh.hpp"
#include "runtime/rendering/mesh.h"
#include "runtime/rendering/shader.h"
#include "runtime/rendering/texture.h"
#include <array>
#include <fstream>

class material;
struct prefab;
struct scene;

namespace asset_compiler
{
std::string escape_str(const std::string& str)
{
	return "\"" + str + "\"";
}

bool run_compile_process(const std::string& process, const std::vector<std::string>& args_array,
						 std::string& err)
{

	std::string args;
	size_t i = 0;
	for(const auto& arg : args_array)
	{
		if(arg.front() == '-')
		{
			args += arg;
		}
		else
		{
			args += escape_str(arg);
		}

		if(i++ != args_array.size() - 1)
			args += " ";
	}

	bx::Error error;
	bx::ProcessReader process_reader;

	auto executable_dir = fs::resolve_protocol("binary:/");
	auto process_full = executable_dir / process;
#if($on($windows))
	process_reader.open((process_full.string() + " " + args).c_str(), "", &error);
#else
    process_reader.open(process_full.string().c_str(), args.c_str(), &error);
#endif
	if(!error.isOk())
	{
		err = std::string(error.getMessage().getPtr());
		return false;
	}
	else
	{
		char buffer[2048];
		process_reader.read(buffer, sizeof(buffer), &error);

		process_reader.close();
		int32_t result = process_reader.getExitCode();

		if(0 != result)
		{
			err = std::string(error.getMessage().getPtr());
			return false;
		}

		return true;
	}
}

template <>
void compile<prefab>(const fs::path&)
{
}

template <>
void compile<scene>(const fs::path&)
{
}

template <>
void compile<material>(const fs::path&)
{
}

template <>
void compile<shader>(const fs::path& absolute_key)
{
	fs::path output = absolute_key.string() + extensions::get_compiled_format<shader>();
	std::string str_input = absolute_key.string();
	std::string file = absolute_key.stem().string();
	fs::path dir = absolute_key.parent_path();

	fs::error_code err;
	fs::path temp = fs::temp_directory_path(err);
	temp /= uuids::random_uuid(str_input).to_string() + ".buildtemp";

	std::string str_output = temp.string();
	fs::path include = fs::resolve_protocol("shader_include:/");
	std::string str_include = include.string();
	fs::path varying = dir / (file + ".io");
	std::string str_varying = varying.string();

	std::string str_platform;
	std::string str_profile;
	std::string str_type;

	bool vs = string_utils::begins_with(file, "vs_");
	bool fs = string_utils::begins_with(file, "fs_");
	bool cs = string_utils::begins_with(file, "cs_");

	auto renderer = gfx::getRendererType();
	if(renderer == gfx::RendererType::Direct3D11 || renderer == gfx::RendererType::Direct3D12)
	{
		str_platform = "windows";

		if(vs)
			str_profile = "vs_4_0";
		else if(fs)
			str_profile = "ps_4_0";
		else if(cs)
			str_profile = "cs_5_0";
	}
	else if(renderer == gfx::RendererType::OpenGL)
	{
		str_platform = "linux";

		if(vs || fs)
			str_profile = "120";
		else if(cs)
			str_profile = "430";
	}
	else if(renderer == gfx::RendererType::Metal)
	{
		str_platform = "osx";
		str_profile = "metal";
	}

	if(vs)
		str_type = "vertex";
	else if(fs)
		str_type = "fragment";
	else if(cs)
		str_type = "compute";
	else
		str_type = "unknown";

	const std::vector<std::string> args_array = {
		"-f",		  str_input.c_str(),	"-o",			str_output.c_str(),
		"-i",		  str_include.c_str(),  "--varyingdef", str_varying.c_str(),
		"--platform", str_platform.c_str(), "-p",			str_profile.c_str(),
		"--type",	 str_type.c_str(),		"-O",			"3",
	};

	std::string error;

	{
		std::ofstream output_file(str_output);
	}

	if(!run_compile_process("shaderc", args_array, error))
	{
		APPLOG_ERROR("Failed compilation of {0} with error: {1}", str_input, error);
	}
	else
	{
		APPLOG_INFO("Successful compilation of {0}", str_input);
		fs::copy_file(temp, output, fs::copy_option::overwrite_if_exists, err);
	}
	fs::remove(temp, err);
}

template <>
void compile<texture>(const fs::path& absolute_key)
{
	fs::path output = absolute_key.string() + extensions::get_compiled_format<texture>();
	std::string str_input = absolute_key.string();

	fs::error_code err;
	fs::path temp = fs::temp_directory_path(err);
    temp /= uuids::random_uuid(str_input).to_string() + ".buildtemp";

	std::string str_output = temp.string();

	const std::vector<std::string> args_array = {
		"-f", str_input.c_str(), "-o", str_output.c_str(), "--as", "ktx", "-m", "-t", "BGRA8",
	};

	std::string error;

	{
		std::ofstream output_file(str_output);
	}

	if(!run_compile_process("texturec", args_array, error))
	{
		APPLOG_ERROR("Failed compilation of {0} with error: {1}", str_input, error);
	}
	else
	{
		APPLOG_INFO("Successful compilation of {0}", str_input);
		fs::copy_file(temp, output, fs::copy_option::overwrite_if_exists, err);
	}
	fs::remove(temp, err);
}

template <>
void compile<mesh>(const fs::path& absolute_key)
{
	fs::path output = absolute_key.string() + extensions::get_compiled_format<mesh>();
	std::string str_input = absolute_key.string();

	fs::error_code err;
	fs::path temp = fs::temp_directory_path(err);
    temp /= uuids::random_uuid(str_input).to_string() + ".buildtemp";

	mesh::load_data data;
	std::vector<animation> animations;
	if(!importer::load_mesh_data_from_file(str_input, data, animations))
	{
		APPLOG_ERROR("Failed compilation of {0}", str_input);
		return;
	}

	if(data.vertex_data.empty() == false)
	{
		{
			std::ofstream soutput(temp.string(), std::ios::out | std::ios::binary);
			cereal::oarchive_binary_t ar(soutput);
			try_save(ar, cereal::make_nvp("mesh", data));
		}
		fs::copy_file(temp, output, fs::copy_option::overwrite_if_exists, err);
		fs::remove(temp, err);

		APPLOG_INFO("Successful compilation of {0}", str_input);
		{
			fs::path file = absolute_key.stem();
			fs::path dir = absolute_key.parent_path();

			for(const auto& animation : animations)
			{
				temp = fs::temp_directory_path(err);
				temp.append(uuids::random_uuid(str_input).to_string() + ".buildtemp");
				{
					std::ofstream soutput(temp.string(), std::ios::out | std::ios::binary);
					cereal::oarchive_binary_t ar(soutput);
					try_save(ar, cereal::make_nvp("animation", animation));
				}
				output = (dir / file).string() + "_" + animation.name + extensions::animation;

				fs::copy_file(temp, output, fs::copy_option::overwrite_if_exists, err);
				fs::remove(temp, err);
			}
		}
	}
}
}
<|endoftext|>


<commit_before>#include <Control/Setting.hh>
#include <Control/ControlData.hh>

#include <iostream>
#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>

Setting::Setting(){
  setDefaults();
}

void Setting::setDefaults(){
  setTessdataDefault();
  setTesseractDefaults();
  setInterfaceDefaults();
  setResourceDefaults();
}

void Setting::setInterfaceDefaults(){
  appName = "Decipher Text";
  interfaceLanguage = "en_US";
  windowState = false;
  windowXPos = 0;
  windowYPos = 0;
  windowWidth = 0;
  windowHeight = 0;
}

void Setting::setResourceDefaults(){
  binRoot = QCoreApplication::applicationDirPath();
  decipherDataPath = binRoot + "/../share/decipher_text";
  iconDir = decipherDataPath + "/icons";
}

void Setting::setTessdataDefault(){
  /*
    ALERT: Make this cross platform!!
  */

  QString path;

  if (QDir("/usr/share/tessdata").exists()){
    path = "/usr/share";
  } else if(QDir("/usr/local/share/tessdata").exists()){
    path = "/usr/local/share";
  } else {
    path = "";
  }

  setTessdataPath(path);
}

void Setting::setTesseractDefaults(){
  /*
    ALERT: Make this cross platform!!
  */
  QFileInfo location1;
  QFileInfo location2;
  QString path;

  location1.setFile("/usr/bin/tesseract");
  location2.setFile("/usr/local/bin/tesseract");

  if(location1.exists() && location1.isFile()){
    path = "/usr/bin/tesseract";
  } else if(location2.exists() && location2.isFile()) {
    path = "/usr/local/bin/tesseract";
  } else {
    path = "";
  }

  setTessdataPath(path);
}

//Getters
QString Setting::getTesseractPath(){
  return tesseractPath;
}

QString Setting::getTessdataPath(){
  return tessdataPath;
}

QString Setting::getAppName(){
  return appName;
}

QString Setting::getInterfaceLanguage(){
  return interfaceLanguage;
}

bool Setting::getWindowState(){
  return windowState;
}

int Setting::getWindowXPos(){
  return windowXPos;
}

int Setting::getWindowYPos(){
  return windowYPos;
}

int Setting::getWindowWidth(){
  return windowWidth;
}

int Setting::getWindowHeight(){
  return windowHeight;
}

QString Setting::getDecipherDataPath(){
  return decipherDataPath;
}

QString Setting::getIconDir(){
  return iconDir;
}

//Setters
void Setting::setTesseractPath(QString path){
  tesseractPath = path;
}

void Setting::setTessdataPath(QString path){
  tessdataPath = path;
}

void Setting::setAppName(QString name){
  appName = name;
}

void Setting::setInterfaceLanguage(QString lang){
  interfaceLanguage = lang;
}

void Setting::setWindowState(bool state){
  windowState = state;
}

void Setting::setWindowXPos(int pos){
  windowXPos = pos;
}

void Setting::setWindowYPos(int pos){
  windowYPos = pos;
}

void Setting::setWindowWidth(int width){
  windowWidth = width;
}

void Setting::setWindowHeight(int height){
  windowHeight = height;
}

void Setting::setDecipherDataPath(QString path){
  decipherDataPath = path;
}<commit_msg>Made Control.Setting search some default paths on windows too.<commit_after>#include <Control/Setting.hh>
#include <Control/ControlData.hh>

#include <iostream>
#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>

Setting::Setting(){
  setDefaults();
}

void Setting::setDefaults(){
  setTessdataDefault();
  setTesseractDefaults();
  setInterfaceDefaults();
  setResourceDefaults();
}

void Setting::setInterfaceDefaults(){
  appName = "Decipher Text";
  interfaceLanguage = "en_US";
  windowState = false;
  windowXPos = 0;
  windowYPos = 0;
  windowWidth = 0;
  windowHeight = 0;
}

void Setting::setResourceDefaults(){
  binRoot = QCoreApplication::applicationDirPath();
  decipherDataPath = binRoot + "/../share/decipher_text";
  iconDir = decipherDataPath + "/icons";
}

void Setting::setTessdataDefault(){
  QString path;

  if (QDir("/usr/share/tessdata").exists()){
    path = "/usr/share";
  } else if(QDir("/usr/local/share/tessdata").exists()){
    path = "/usr/local/share";
  } else {
    path = "";
  }

  #ifdef _WIN32
    if (QDir("C:\\Tesseract-OCR\\tessdata").exists()){
      path = "C:\\Tesseract-OCR";
    } else if(QDir("C:\\Tesseract\\tessdata").exists()){
      path = "C:\\Tesseract";
    } else if(QDir("C:\\Program Files\\Tesseract-OCR\\tessdata").exists()){
      path = "C:\\Program Files\\Tesseract-OCR";
    } else if(QDir("C:\\Program Files (x86)\\Tesseract-OCR\\tessdata").exists()){
      path = "C:\\Program Files (x86)\\Tesseract-OCR";
    } else if(QDir("C:\\Program Files\\Tesseract\\tessdata").exists()){
      path = "C:\\Program Files\\Tesseract";
    } else if(QDir("C:\\Program Files (x86)\\Tesseract\\tessdata").exists()){
      path = "C:\\Program Files (x86)\\Tesseract";
    } else {
      path = "";
    }
  #endif

  setTessdataPath(path);
}

void Setting::setTesseractDefaults(){
  QFileInfo location1;
  QFileInfo location2;
  QString path;

  #ifdef _WIN32
  location1.setFile("C:\\Program Files (x86)\\Tesseract-OCR\\tesseract.exe");
  location2.setFile("C:\\Tesseract-OCR\\tesseract.exe");
  #else
  location1.setFile("/usr/bin/tesseract");
  location2.setFile("/usr/local/bin/tesseract");
  #endif

  if(location1.exists() && location1.isFile()){
    path = location1.absoluteFilePath();
  } else if(location2.exists() && location2.isFile()) {
    path = location1.absoluteFilePath();
  } else {
    path = "";
  }

  setTessdataPath(path);
}

//Getters
QString Setting::getTesseractPath(){
  return tesseractPath;
}

QString Setting::getTessdataPath(){
  return tessdataPath;
}

QString Setting::getAppName(){
  return appName;
}

QString Setting::getInterfaceLanguage(){
  return interfaceLanguage;
}

bool Setting::getWindowState(){
  return windowState;
}

int Setting::getWindowXPos(){
  return windowXPos;
}

int Setting::getWindowYPos(){
  return windowYPos;
}

int Setting::getWindowWidth(){
  return windowWidth;
}

int Setting::getWindowHeight(){
  return windowHeight;
}

QString Setting::getDecipherDataPath(){
  return decipherDataPath;
}

QString Setting::getIconDir(){
  return iconDir;
}

//Setters
void Setting::setTesseractPath(QString path){
  tesseractPath = path;
}

void Setting::setTessdataPath(QString path){
  tessdataPath = path;
}

void Setting::setAppName(QString name){
  appName = name;
}

void Setting::setInterfaceLanguage(QString lang){
  interfaceLanguage = lang;
}

void Setting::setWindowState(bool state){
  windowState = state;
}

void Setting::setWindowXPos(int pos){
  windowXPos = pos;
}

void Setting::setWindowYPos(int pos){
  windowYPos = pos;
}

void Setting::setWindowWidth(int width){
  windowWidth = width;
}

void Setting::setWindowHeight(int height){
  windowHeight = height;
}

void Setting::setDecipherDataPath(QString path){
  decipherDataPath = path;
}<|endoftext|>