add ipc
This commit is contained in:
parent
fcf8cfc7f4
commit
25c023e479
68
Thirdparty/libipc/include/libipc/buffer.h
vendored
Normal file
68
Thirdparty/libipc/include/libipc/buffer.h
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
|
||||
#include "libipc/export.h"
|
||||
#include "libipc/def.h"
|
||||
|
||||
namespace ipc {
|
||||
|
||||
class IPC_EXPORT buffer {
|
||||
public:
|
||||
using destructor_t = void (*)(void*, std::size_t);
|
||||
|
||||
buffer();
|
||||
|
||||
buffer(void* p, std::size_t s, destructor_t d);
|
||||
buffer(void* p, std::size_t s, destructor_t d, void* additional);
|
||||
buffer(void* p, std::size_t s);
|
||||
|
||||
template <std::size_t N>
|
||||
explicit buffer(byte_t const (& data)[N])
|
||||
: buffer(data, sizeof(data)) {
|
||||
}
|
||||
explicit buffer(char const & c);
|
||||
|
||||
buffer(buffer&& rhs);
|
||||
~buffer();
|
||||
|
||||
void swap(buffer& rhs);
|
||||
buffer& operator=(buffer rhs);
|
||||
|
||||
bool empty() const noexcept;
|
||||
|
||||
void * data() noexcept;
|
||||
void const * data() const noexcept;
|
||||
|
||||
template <typename T>
|
||||
T get() const { return T(data()); }
|
||||
|
||||
std::size_t size() const noexcept;
|
||||
|
||||
std::tuple<void*, std::size_t> to_tuple() {
|
||||
return std::make_tuple(data(), size());
|
||||
}
|
||||
|
||||
std::tuple<void const *, std::size_t> to_tuple() const {
|
||||
return std::make_tuple(data(), size());
|
||||
}
|
||||
|
||||
std::vector<byte_t> to_vector() const {
|
||||
return {
|
||||
get<byte_t const *>(),
|
||||
get<byte_t const *>() + size()
|
||||
};
|
||||
}
|
||||
|
||||
friend IPC_EXPORT bool operator==(buffer const & b1, buffer const & b2);
|
||||
friend IPC_EXPORT bool operator!=(buffer const & b1, buffer const & b2);
|
||||
|
||||
private:
|
||||
class buffer_;
|
||||
buffer_* p_;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
39
Thirdparty/libipc/include/libipc/condition.h
vendored
Normal file
39
Thirdparty/libipc/include/libipc/condition.h
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // std::uint64_t
|
||||
|
||||
#include "libipc/export.h"
|
||||
#include "libipc/def.h"
|
||||
#include "libipc/mutex.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace sync {
|
||||
|
||||
class IPC_EXPORT condition {
|
||||
condition(condition const &) = delete;
|
||||
condition &operator=(condition const &) = delete;
|
||||
|
||||
public:
|
||||
condition();
|
||||
explicit condition(char const *name);
|
||||
~condition();
|
||||
|
||||
void const *native() const noexcept;
|
||||
void *native() noexcept;
|
||||
|
||||
bool valid() const noexcept;
|
||||
|
||||
bool open(char const *name) noexcept;
|
||||
void close() noexcept;
|
||||
|
||||
bool wait(ipc::sync::mutex &mtx, std::uint64_t tm = ipc::invalid_value) noexcept;
|
||||
bool notify() noexcept;
|
||||
bool broadcast() noexcept;
|
||||
|
||||
private:
|
||||
class condition_;
|
||||
condition_* p_;
|
||||
};
|
||||
|
||||
} // namespace sync
|
||||
} // namespace ipc
|
68
Thirdparty/libipc/include/libipc/def.h
vendored
Normal file
68
Thirdparty/libipc/include/libipc/def.h
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits> // std::numeric_limits
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
namespace ipc {
|
||||
|
||||
// types
|
||||
|
||||
using byte_t = std::uint8_t;
|
||||
|
||||
template <std::size_t N>
|
||||
struct uint;
|
||||
|
||||
template <> struct uint<8 > { using type = std::uint8_t ; };
|
||||
template <> struct uint<16> { using type = std::uint16_t; };
|
||||
template <> struct uint<32> { using type = std::uint32_t; };
|
||||
template <> struct uint<64> { using type = std::uint64_t; };
|
||||
|
||||
template <std::size_t N>
|
||||
using uint_t = typename uint<N>::type;
|
||||
|
||||
// constants
|
||||
|
||||
enum : std::uint32_t {
|
||||
invalid_value = (std::numeric_limits<std::uint32_t>::max)(),
|
||||
default_timeout = 100, // ms
|
||||
};
|
||||
|
||||
enum : std::size_t {
|
||||
data_length = 64,
|
||||
large_msg_limit = data_length,
|
||||
large_msg_align = 1024,
|
||||
large_msg_cache = 32,
|
||||
};
|
||||
|
||||
enum class relat { // multiplicity of the relationship
|
||||
single,
|
||||
multi
|
||||
};
|
||||
|
||||
enum class trans { // transmission
|
||||
unicast,
|
||||
broadcast
|
||||
};
|
||||
|
||||
// producer-consumer policy flag
|
||||
|
||||
template <relat Rp, relat Rc, trans Ts>
|
||||
struct wr {};
|
||||
|
||||
template <typename WR>
|
||||
struct relat_trait;
|
||||
|
||||
template <relat Rp, relat Rc, trans Ts>
|
||||
struct relat_trait<wr<Rp, Rc, Ts>> {
|
||||
constexpr static bool is_multi_producer = (Rp == relat::multi);
|
||||
constexpr static bool is_multi_consumer = (Rc == relat::multi);
|
||||
constexpr static bool is_broadcast = (Ts == trans::broadcast);
|
||||
};
|
||||
|
||||
template <template <typename> class Policy, typename Flag>
|
||||
struct relat_trait<Policy<Flag>> : relat_trait<Flag> {};
|
||||
|
||||
} // namespace ipc
|
54
Thirdparty/libipc/include/libipc/export.h
vendored
Normal file
54
Thirdparty/libipc/include/libipc/export.h
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(Q_DECL_EXPORT) && defined(Q_DECL_IMPORT)
|
||||
|
||||
# define IPC_DECL_EXPORT Q_DECL_EXPORT
|
||||
# define IPC_DECL_IMPORT Q_DECL_IMPORT
|
||||
|
||||
#else // defined(Q_DECL_EXPORT) && defined(Q_DECL_IMPORT)
|
||||
|
||||
/*
|
||||
* Compiler & system detection for IPC_DECL_EXPORT & IPC_DECL_IMPORT.
|
||||
* Not using QtCore cause it shouldn't depend on Qt.
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define IPC_DECL_EXPORT __declspec(dllexport)
|
||||
# define IPC_DECL_IMPORT __declspec(dllimport)
|
||||
#elif defined(__ARMCC__) || defined(__CC_ARM)
|
||||
# if defined(ANDROID) || defined(__linux__) || defined(__linux)
|
||||
# define IPC_DECL_EXPORT __attribute__((visibility("default")))
|
||||
# define IPC_DECL_IMPORT __attribute__((visibility("default")))
|
||||
# else
|
||||
# define IPC_DECL_EXPORT __declspec(dllexport)
|
||||
# define IPC_DECL_IMPORT __declspec(dllimport)
|
||||
# endif
|
||||
#elif defined(__GNUC__)
|
||||
# if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || \
|
||||
defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
|
||||
# define IPC_DECL_EXPORT __declspec(dllexport)
|
||||
# define IPC_DECL_IMPORT __declspec(dllimport)
|
||||
# else
|
||||
# define IPC_DECL_EXPORT __attribute__((visibility("default")))
|
||||
# define IPC_DECL_IMPORT __attribute__((visibility("default")))
|
||||
# endif
|
||||
#else
|
||||
# define IPC_DECL_EXPORT __attribute__((visibility("default")))
|
||||
# define IPC_DECL_IMPORT __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
#endif // defined(Q_DECL_EXPORT) && defined(Q_DECL_IMPORT)
|
||||
|
||||
/*
|
||||
* Define IPC_EXPORT for exporting function & class.
|
||||
*/
|
||||
|
||||
#ifndef IPC_EXPORT
|
||||
#if defined(LIBIPC_LIBRARY_SHARED_BUILDING__)
|
||||
# define IPC_EXPORT IPC_DECL_EXPORT
|
||||
#elif defined(LIBIPC_LIBRARY_SHARED_USING__)
|
||||
# define IPC_EXPORT IPC_DECL_IMPORT
|
||||
#else
|
||||
# define IPC_EXPORT
|
||||
#endif
|
||||
#endif /*IPC_EXPORT*/
|
192
Thirdparty/libipc/include/libipc/ipc.h
vendored
Normal file
192
Thirdparty/libipc/include/libipc/ipc.h
vendored
Normal file
@ -0,0 +1,192 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "libipc/export.h"
|
||||
#include "libipc/def.h"
|
||||
#include "libipc/buffer.h"
|
||||
#include "libipc/shm.h"
|
||||
|
||||
namespace ipc {
|
||||
|
||||
using handle_t = void*;
|
||||
using buff_t = buffer;
|
||||
|
||||
enum : unsigned {
|
||||
sender,
|
||||
receiver
|
||||
};
|
||||
|
||||
template <typename Flag>
|
||||
struct IPC_EXPORT chan_impl {
|
||||
static bool connect (ipc::handle_t * ph, char const * name, unsigned mode);
|
||||
static bool reconnect (ipc::handle_t * ph, unsigned mode);
|
||||
static void disconnect(ipc::handle_t h);
|
||||
static void destroy (ipc::handle_t h);
|
||||
|
||||
static char const * name(ipc::handle_t h);
|
||||
|
||||
static std::size_t recv_count(ipc::handle_t h);
|
||||
static bool wait_for_recv(ipc::handle_t h, std::size_t r_count, std::uint64_t tm);
|
||||
|
||||
static bool send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm);
|
||||
static buff_t recv(ipc::handle_t h, std::uint64_t tm);
|
||||
|
||||
static bool try_send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm);
|
||||
static buff_t try_recv(ipc::handle_t h);
|
||||
};
|
||||
|
||||
template <typename Flag>
|
||||
class chan_wrapper {
|
||||
private:
|
||||
using detail_t = chan_impl<Flag>;
|
||||
|
||||
ipc::handle_t h_ = nullptr;
|
||||
unsigned mode_ = ipc::sender;
|
||||
bool connected_ = false;
|
||||
|
||||
public:
|
||||
chan_wrapper() noexcept = default;
|
||||
|
||||
explicit chan_wrapper(char const * name, unsigned mode = ipc::sender)
|
||||
: connected_{this->connect(name, mode)} {
|
||||
}
|
||||
|
||||
chan_wrapper(chan_wrapper&& rhs) noexcept
|
||||
: chan_wrapper{} {
|
||||
swap(rhs);
|
||||
}
|
||||
|
||||
~chan_wrapper() {
|
||||
detail_t::destroy(h_);
|
||||
}
|
||||
|
||||
void swap(chan_wrapper& rhs) noexcept {
|
||||
std::swap(h_ , rhs.h_);
|
||||
std::swap(mode_ , rhs.mode_);
|
||||
std::swap(connected_, rhs.connected_);
|
||||
}
|
||||
|
||||
chan_wrapper& operator=(chan_wrapper rhs) noexcept {
|
||||
swap(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
char const * name() const noexcept {
|
||||
return detail_t::name(h_);
|
||||
}
|
||||
|
||||
ipc::handle_t handle() const noexcept {
|
||||
return h_;
|
||||
}
|
||||
|
||||
bool valid() const noexcept {
|
||||
return (handle() != nullptr);
|
||||
}
|
||||
|
||||
unsigned mode() const noexcept {
|
||||
return mode_;
|
||||
}
|
||||
|
||||
chan_wrapper clone() const {
|
||||
return chan_wrapper { name(), mode_ };
|
||||
}
|
||||
|
||||
/**
|
||||
* Building handle, then try connecting with name & mode flags.
|
||||
*/
|
||||
bool connect(char const * name, unsigned mode = ipc::sender | ipc::receiver) {
|
||||
if (name == nullptr || name[0] == '\0') return false;
|
||||
detail_t::disconnect(h_); // clear old connection
|
||||
return connected_ = detail_t::connect(&h_, name, mode_ = mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try connecting with new mode flags.
|
||||
*/
|
||||
bool reconnect(unsigned mode) {
|
||||
if (!valid()) return false;
|
||||
if (connected_ && (mode_ == mode)) return true;
|
||||
return connected_ = detail_t::reconnect(&h_, mode_ = mode);
|
||||
}
|
||||
|
||||
void disconnect() {
|
||||
if (!valid()) return;
|
||||
detail_t::disconnect(h_);
|
||||
connected_ = false;
|
||||
}
|
||||
|
||||
std::size_t recv_count() const {
|
||||
return detail_t::recv_count(h_);
|
||||
}
|
||||
|
||||
bool wait_for_recv(std::size_t r_count, std::uint64_t tm = invalid_value) const {
|
||||
return detail_t::wait_for_recv(h_, r_count, tm);
|
||||
}
|
||||
|
||||
static bool wait_for_recv(char const * name, std::size_t r_count, std::uint64_t tm = invalid_value) {
|
||||
return chan_wrapper(name).wait_for_recv(r_count, tm);
|
||||
}
|
||||
|
||||
/**
|
||||
* If timeout, this function would call 'force_push' to send the data forcibly.
|
||||
*/
|
||||
bool send(void const * data, std::size_t size, std::uint64_t tm = default_timeout) {
|
||||
return detail_t::send(h_, data, size, tm);
|
||||
}
|
||||
bool send(buff_t const & buff, std::uint64_t tm = default_timeout) {
|
||||
return this->send(buff.data(), buff.size(), tm);
|
||||
}
|
||||
bool send(std::string const & str, std::uint64_t tm = default_timeout) {
|
||||
return this->send(str.c_str(), str.size() + 1, tm);
|
||||
}
|
||||
|
||||
/**
|
||||
* If timeout, this function would just return false.
|
||||
*/
|
||||
bool try_send(void const * data, std::size_t size, std::uint64_t tm = default_timeout) {
|
||||
return detail_t::try_send(h_, data, size, tm);
|
||||
}
|
||||
bool try_send(buff_t const & buff, std::uint64_t tm = default_timeout) {
|
||||
return this->try_send(buff.data(), buff.size(), tm);
|
||||
}
|
||||
bool try_send(std::string const & str, std::uint64_t tm = default_timeout) {
|
||||
return this->try_send(str.c_str(), str.size() + 1, tm);
|
||||
}
|
||||
|
||||
buff_t recv(std::uint64_t tm = invalid_value) {
|
||||
return detail_t::recv(h_, tm);
|
||||
}
|
||||
|
||||
buff_t try_recv() {
|
||||
return detail_t::try_recv(h_);
|
||||
}
|
||||
};
|
||||
|
||||
template <relat Rp, relat Rc, trans Ts>
|
||||
using chan = chan_wrapper<ipc::wr<Rp, Rc, Ts>>;
|
||||
|
||||
/**
|
||||
* class route
|
||||
*
|
||||
* You could use one producer/server/sender for sending messages to a route,
|
||||
* then all the consumers/clients/receivers which are receiving with this route,
|
||||
* would receive your sent messages.
|
||||
*
|
||||
* A route could only be used in 1 to N
|
||||
* (one producer/writer to multi consumers/readers)
|
||||
*/
|
||||
|
||||
using route = chan<relat::single, relat::multi, trans::broadcast>;
|
||||
|
||||
/**
|
||||
* class channel
|
||||
*
|
||||
* You could use multi producers/writers for sending messages to a channel,
|
||||
* then all the consumers/readers which are receiving with this channel,
|
||||
* would receive your sent messages.
|
||||
*/
|
||||
|
||||
using channel = chan<relat::multi, relat::multi, trans::broadcast>;
|
||||
|
||||
} // namespace ipc
|
39
Thirdparty/libipc/include/libipc/mutex.h
vendored
Normal file
39
Thirdparty/libipc/include/libipc/mutex.h
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // std::uint64_t
|
||||
#include <system_error>
|
||||
|
||||
#include "libipc/export.h"
|
||||
#include "libipc/def.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace sync {
|
||||
|
||||
class IPC_EXPORT mutex {
|
||||
mutex(mutex const &) = delete;
|
||||
mutex &operator=(mutex const &) = delete;
|
||||
|
||||
public:
|
||||
mutex();
|
||||
explicit mutex(char const *name);
|
||||
~mutex();
|
||||
|
||||
void const *native() const noexcept;
|
||||
void *native() noexcept;
|
||||
|
||||
bool valid() const noexcept;
|
||||
|
||||
bool open(char const *name) noexcept;
|
||||
void close() noexcept;
|
||||
|
||||
bool lock(std::uint64_t tm = ipc::invalid_value) noexcept;
|
||||
bool try_lock() noexcept(false); // std::system_error
|
||||
bool unlock() noexcept;
|
||||
|
||||
private:
|
||||
class mutex_;
|
||||
mutex_* p_;
|
||||
};
|
||||
|
||||
} // namespace sync
|
||||
} // namespace ipc
|
103
Thirdparty/libipc/include/libipc/pool_alloc.h
vendored
Normal file
103
Thirdparty/libipc/include/libipc/pool_alloc.h
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
#include "libipc/export.h"
|
||||
#include "libipc/def.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace mem {
|
||||
|
||||
class IPC_EXPORT pool_alloc {
|
||||
public:
|
||||
static void* alloc(std::size_t size);
|
||||
static void free (void* p, std::size_t size);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
/// construct/destruct an object
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct impl {
|
||||
template <typename... P>
|
||||
static T* construct(T* p, P&&... params) {
|
||||
::new (p) T(std::forward<P>(params)...);
|
||||
return p;
|
||||
}
|
||||
|
||||
static void destruct(T* p) {
|
||||
reinterpret_cast<T*>(p)->~T();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, size_t N>
|
||||
struct impl<T[N]> {
|
||||
using type = T[N];
|
||||
|
||||
template <typename... P>
|
||||
static type* construct(type* p, P&&... params) {
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
impl<T>::construct(&((*p)[i]), std::forward<P>(params)...);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static void destruct(type* p) {
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
impl<T>::destruct(&((*p)[i]));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, typename... P>
|
||||
T* construct(T* p, P&&... params) {
|
||||
return detail::impl<T>::construct(p, std::forward<P>(params)...);
|
||||
}
|
||||
|
||||
template <typename T, typename... P>
|
||||
T* construct(void* p, P&&... params) {
|
||||
return construct(static_cast<T*>(p), std::forward<P>(params)...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void destruct(T* p) {
|
||||
return detail::impl<T>::destruct(p);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void destruct(void* p) {
|
||||
destruct(static_cast<T*>(p));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
/// general alloc/free
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void* alloc(std::size_t size) {
|
||||
return pool_alloc::alloc(size);
|
||||
}
|
||||
|
||||
template <typename T, typename... P>
|
||||
T* alloc(P&&... params) {
|
||||
return construct<T>(pool_alloc::alloc(sizeof(T)), std::forward<P>(params)...);
|
||||
}
|
||||
|
||||
inline void free(void* p, std::size_t size) {
|
||||
pool_alloc::free(p, size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void free(T* p) {
|
||||
if (p == nullptr) return;
|
||||
destruct(p);
|
||||
pool_alloc::free(p, sizeof(T));
|
||||
}
|
||||
|
||||
} // namespace mem
|
||||
} // namespace ipc
|
171
Thirdparty/libipc/include/libipc/rw_lock.h
vendored
Normal file
171
Thirdparty/libipc/include/libipc/rw_lock.h
vendored
Normal file
@ -0,0 +1,171 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
/// Gives hint to processor that improves performance of spin-wait loops.
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma push_macro("IPC_LOCK_PAUSE_")
|
||||
#undef IPC_LOCK_PAUSE_
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <windows.h> // YieldProcessor
|
||||
/*
|
||||
See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms687419(v=vs.85).aspx
|
||||
Not for intel c++ compiler, so ignore http://software.intel.com/en-us/forums/topic/296168
|
||||
*/
|
||||
# define IPC_LOCK_PAUSE_() YieldProcessor()
|
||||
#elif defined(__GNUC__)
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
/*
|
||||
See: Intel(R) 64 and IA-32 Architectures Software Developer's Manual V2
|
||||
PAUSE-Spin Loop Hint, 4-57
|
||||
http://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.html?wapkw=instruction+set+reference
|
||||
*/
|
||||
# define IPC_LOCK_PAUSE_() __asm__ __volatile__("pause")
|
||||
#elif defined(__ia64__) || defined(__ia64)
|
||||
/*
|
||||
See: Intel(R) Itanium(R) Architecture Developer's Manual, Vol.3
|
||||
hint - Performance Hint, 3:145
|
||||
http://www.intel.com/content/www/us/en/processors/itanium/itanium-architecture-vol-3-manual.html
|
||||
*/
|
||||
# define IPC_LOCK_PAUSE_() __asm__ __volatile__ ("hint @pause")
|
||||
#elif defined(__arm__)
|
||||
/*
|
||||
See: ARM Architecture Reference Manuals (YIELD)
|
||||
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.subset.architecture.reference/index.html
|
||||
*/
|
||||
# define IPC_LOCK_PAUSE_() __asm__ __volatile__ ("yield")
|
||||
#endif
|
||||
#endif/*compilers*/
|
||||
|
||||
#if !defined(IPC_LOCK_PAUSE_)
|
||||
/*
|
||||
Just use a compiler fence, prevent compiler from optimizing loop
|
||||
*/
|
||||
# define IPC_LOCK_PAUSE_() std::atomic_signal_fence(std::memory_order_seq_cst)
|
||||
#endif/*!defined(IPC_LOCK_PAUSE_)*/
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
/// Yield to other threads
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace ipc {
|
||||
|
||||
template <typename K>
|
||||
inline void yield(K& k) noexcept {
|
||||
if (k < 4) { /* Do nothing */ }
|
||||
else
|
||||
if (k < 16) { IPC_LOCK_PAUSE_(); }
|
||||
else
|
||||
if (k < 32) { std::this_thread::yield(); }
|
||||
else {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
return;
|
||||
}
|
||||
++k;
|
||||
}
|
||||
|
||||
template <std::size_t N = 32, typename K, typename F>
|
||||
inline void sleep(K& k, F&& f) {
|
||||
if (k < static_cast<K>(N)) {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
else {
|
||||
static_cast<void>(std::forward<F>(f)());
|
||||
return;
|
||||
}
|
||||
++k;
|
||||
}
|
||||
|
||||
template <std::size_t N = 32, typename K>
|
||||
inline void sleep(K& k) {
|
||||
sleep<N>(k, [] {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
|
||||
#pragma pop_macro("IPC_LOCK_PAUSE_")
|
||||
|
||||
namespace ipc {
|
||||
|
||||
class spin_lock {
|
||||
std::atomic<unsigned> lc_ { 0 };
|
||||
|
||||
public:
|
||||
void lock(void) noexcept {
|
||||
for (unsigned k = 0;
|
||||
lc_.exchange(1, std::memory_order_acquire);
|
||||
yield(k)) ;
|
||||
}
|
||||
|
||||
void unlock(void) noexcept {
|
||||
lc_.store(0, std::memory_order_release);
|
||||
}
|
||||
};
|
||||
|
||||
class rw_lock {
|
||||
using lc_ui_t = unsigned;
|
||||
|
||||
std::atomic<lc_ui_t> lc_ { 0 };
|
||||
|
||||
enum : lc_ui_t {
|
||||
w_mask = (std::numeric_limits<std::make_signed_t<lc_ui_t>>::max)(), // b 0111 1111
|
||||
w_flag = w_mask + 1 // b 1000 0000
|
||||
};
|
||||
|
||||
public:
|
||||
rw_lock() = default;
|
||||
|
||||
rw_lock(const rw_lock&) = delete;
|
||||
rw_lock& operator=(const rw_lock&) = delete;
|
||||
rw_lock(rw_lock&&) = delete;
|
||||
rw_lock& operator=(rw_lock&&) = delete;
|
||||
|
||||
void lock() noexcept {
|
||||
for (unsigned k = 0;;) {
|
||||
auto old = lc_.fetch_or(w_flag, std::memory_order_acq_rel);
|
||||
if (!old) return; // got w-lock
|
||||
if (!(old & w_flag)) break; // other thread having r-lock
|
||||
yield(k); // other thread having w-lock
|
||||
}
|
||||
// wait for reading finished
|
||||
for (unsigned k = 0;
|
||||
lc_.load(std::memory_order_acquire) & w_mask;
|
||||
yield(k)) ;
|
||||
}
|
||||
|
||||
void unlock() noexcept {
|
||||
lc_.store(0, std::memory_order_release);
|
||||
}
|
||||
|
||||
void lock_shared() noexcept {
|
||||
auto old = lc_.load(std::memory_order_acquire);
|
||||
for (unsigned k = 0;;) {
|
||||
// if w_flag set, just continue
|
||||
if (old & w_flag) {
|
||||
yield(k);
|
||||
old = lc_.load(std::memory_order_acquire);
|
||||
}
|
||||
// otherwise try cas lc + 1 (set r-lock)
|
||||
else if (lc_.compare_exchange_weak(old, old + 1, std::memory_order_release)) {
|
||||
return;
|
||||
}
|
||||
// set r-lock failed, old has been updated
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_shared() noexcept {
|
||||
lc_.fetch_sub(1, std::memory_order_release);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ipc
|
37
Thirdparty/libipc/include/libipc/semaphore.h
vendored
Normal file
37
Thirdparty/libipc/include/libipc/semaphore.h
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // std::uint64_t
|
||||
|
||||
#include "libipc/export.h"
|
||||
#include "libipc/def.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace sync {
|
||||
|
||||
class IPC_EXPORT semaphore {
|
||||
semaphore(semaphore const &) = delete;
|
||||
semaphore &operator=(semaphore const &) = delete;
|
||||
|
||||
public:
|
||||
semaphore();
|
||||
explicit semaphore(char const *name, std::uint32_t count = 0);
|
||||
~semaphore();
|
||||
|
||||
void const *native() const noexcept;
|
||||
void *native() noexcept;
|
||||
|
||||
bool valid() const noexcept;
|
||||
|
||||
bool open(char const *name, std::uint32_t count = 0) noexcept;
|
||||
void close() noexcept;
|
||||
|
||||
bool wait(std::uint64_t tm = ipc::invalid_value) noexcept;
|
||||
bool post(std::uint32_t count = 1) noexcept;
|
||||
|
||||
private:
|
||||
class semaphore_;
|
||||
semaphore_* p_;
|
||||
};
|
||||
|
||||
} // namespace sync
|
||||
} // namespace ipc
|
59
Thirdparty/libipc/include/libipc/shm.h
vendored
Normal file
59
Thirdparty/libipc/include/libipc/shm.h
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "libipc/export.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace shm {
|
||||
|
||||
using id_t = void*;
|
||||
|
||||
enum : unsigned {
|
||||
create = 0x01,
|
||||
open = 0x02
|
||||
};
|
||||
|
||||
IPC_EXPORT id_t acquire(char const * name, std::size_t size, unsigned mode = create | open);
|
||||
IPC_EXPORT void * get_mem(id_t id, std::size_t * size);
|
||||
IPC_EXPORT std::int32_t release(id_t id);
|
||||
IPC_EXPORT void remove (id_t id);
|
||||
IPC_EXPORT void remove (char const * name);
|
||||
|
||||
IPC_EXPORT std::int32_t get_ref(id_t id);
|
||||
IPC_EXPORT void sub_ref(id_t id);
|
||||
|
||||
class IPC_EXPORT handle {
|
||||
public:
|
||||
handle();
|
||||
handle(char const * name, std::size_t size, unsigned mode = create | open);
|
||||
handle(handle&& rhs);
|
||||
|
||||
~handle();
|
||||
|
||||
void swap(handle& rhs);
|
||||
handle& operator=(handle rhs);
|
||||
|
||||
bool valid() const noexcept;
|
||||
std::size_t size () const noexcept;
|
||||
char const * name () const noexcept;
|
||||
|
||||
std::int32_t ref() const noexcept;
|
||||
void sub_ref() noexcept;
|
||||
|
||||
bool acquire(char const * name, std::size_t size, unsigned mode = create | open);
|
||||
std::int32_t release();
|
||||
|
||||
void* get() const;
|
||||
|
||||
void attach(id_t);
|
||||
id_t detach();
|
||||
|
||||
private:
|
||||
class handle_;
|
||||
handle_* p_;
|
||||
};
|
||||
|
||||
} // namespace shm
|
||||
} // namespace ipc
|
BIN
Thirdparty/libipc/lib/ipc.lib
vendored
Normal file
BIN
Thirdparty/libipc/lib/ipc.lib
vendored
Normal file
Binary file not shown.
BIN
Thirdparty/libipc/lib/ipc_o.lib
vendored
Normal file
BIN
Thirdparty/libipc/lib/ipc_o.lib
vendored
Normal file
Binary file not shown.
BIN
Thirdparty/libipc/lib/ipcd.lib
vendored
Normal file
BIN
Thirdparty/libipc/lib/ipcd.lib
vendored
Normal file
Binary file not shown.
BIN
Thirdparty/libipc/lib/ipcd.pdb
vendored
Normal file
BIN
Thirdparty/libipc/lib/ipcd.pdb
vendored
Normal file
Binary file not shown.
@ -60,6 +60,8 @@ int Application::RunLoop() {
|
||||
|
||||
RHI::Get()->StartRender();
|
||||
|
||||
|
||||
|
||||
mesh_ = new Mesh;
|
||||
mesh_->SetVertices(vertices, 3, false);
|
||||
meshRender_ = new MeshRender(mesh_);
|
||||
|
@ -23,12 +23,14 @@ INCLUDE_DIRECTORIES(
|
||||
${Thirdparty}/glm
|
||||
${Thirdparty}
|
||||
${Thirdparty}/spdlog/include
|
||||
${Thirdparty}/libipc/include
|
||||
)
|
||||
|
||||
link_directories(
|
||||
${Thirdparty}/glfw/lib-vc2022
|
||||
${Thirdparty}/glew/lib
|
||||
${Thirdparty}/spdlog/lib
|
||||
${Thirdparty}/libipc/lib
|
||||
)
|
||||
|
||||
# IF(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
@ -66,6 +68,8 @@ target_link_libraries(
|
||||
glfw3
|
||||
debug spdlogd
|
||||
optimized spdlog
|
||||
debug ipcd
|
||||
optimized ipc
|
||||
)
|
||||
|
||||
|
||||
|
103
src/Ipc/Ipc.cpp
Normal file
103
src/Ipc/Ipc.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#include "Ipc/Ipc.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "Ipc/ReadCallback.h"
|
||||
|
||||
std::shared_ptr<Ipc> Ipc::create(const char* reader_name, const char* writer_name) {
|
||||
struct Creator : public Ipc {
|
||||
Creator(const char* reader_name, const char* writer_name) : Ipc(reader_name, writer_name) {}
|
||||
~Creator() override = default;
|
||||
};
|
||||
return std::make_shared<Creator>(reader_name, writer_name);
|
||||
}
|
||||
|
||||
Ipc::Ipc(const char* reader_name, const char* writer_name) noexcept
|
||||
: reader_name_(reader_name)
|
||||
, writer_name_(writer_name) {
|
||||
sender_ = std::make_unique<ipc::channel>(reader_name_.c_str(), ipc::sender);
|
||||
printf("%s, %s", reader_name, writer_name);
|
||||
}
|
||||
|
||||
Ipc::~Ipc() {
|
||||
stop();
|
||||
}
|
||||
|
||||
bool Ipc::listen() {
|
||||
if (reciver_stop_.load(std::memory_order_acquire)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
reciver_stop_.store(false);
|
||||
|
||||
std::weak_ptr<Ipc> wThis = shared_from_this();
|
||||
reciver_thread_ = std::move(std::thread(std::bind(&Ipc::doReciver, this, wThis)));
|
||||
return true;
|
||||
}
|
||||
|
||||
void Ipc::stop() {
|
||||
if (!reciver_stop_.load(std::memory_order_acquire)) {
|
||||
return;
|
||||
}
|
||||
|
||||
reciver_stop_.store(true, std::memory_order_release);
|
||||
|
||||
sender_->disconnect();
|
||||
receiver_->disconnect();
|
||||
|
||||
if (reciver_thread_.joinable()) {
|
||||
reciver_thread_.join();
|
||||
}
|
||||
}
|
||||
|
||||
bool Ipc::send(const char* data, unsigned int size) {
|
||||
if (!sender_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return sender_->send(data, size);
|
||||
}
|
||||
|
||||
void Ipc::registReadCallback(const std::shared_ptr<IReaderCallback>& reader) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
auto itor = std::find(reader_callbacks_.begin(), reader_callbacks_.end(), reader);
|
||||
if (reader_callbacks_.end() != itor) {
|
||||
return;
|
||||
}
|
||||
reader_callbacks_.emplace_back(reader);
|
||||
}
|
||||
|
||||
void Ipc::unregistReadCallback(const std::shared_ptr<IReaderCallback>& reader) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
auto itor = std::find(reader_callbacks_.begin(), reader_callbacks_.end(), reader);
|
||||
if (reader_callbacks_.end() != itor) {
|
||||
return;
|
||||
}
|
||||
reader_callbacks_.erase(itor);
|
||||
}
|
||||
|
||||
void Ipc::doReciver(std::weak_ptr<Ipc> wThis) {
|
||||
std::shared_ptr<Ipc> self(wThis.lock());
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
|
||||
receiver_ = std::make_unique<ipc::channel>(writer_name_.c_str(), ipc::receiver);
|
||||
while (!reciver_stop_.load(std::memory_order_acquire)) {
|
||||
ipc::buff_t buffer = receiver_->recv();
|
||||
if (buffer.empty()) {
|
||||
break;
|
||||
}
|
||||
const char* data = buffer.get<const char*>();
|
||||
onReciveer(data, static_cast<unsigned int>(buffer.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void Ipc::onReciveer(const char* buffer, unsigned int size) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
for (auto& read : reader_callbacks_) {
|
||||
read->onRead(buffer, size);
|
||||
}
|
||||
}
|
46
src/Ipc/Ipc.h
Normal file
46
src/Ipc/Ipc.h
Normal file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
|
||||
#include <libipc/ipc.h>
|
||||
|
||||
class IReaderCallback;
|
||||
|
||||
class Ipc : public std::enable_shared_from_this<Ipc>{
|
||||
public:
|
||||
static std::shared_ptr<Ipc> create(const char* reader_name, const char* writer_name);
|
||||
public:
|
||||
virtual ~Ipc();
|
||||
|
||||
bool listen();
|
||||
void stop();
|
||||
bool send(const char* data, unsigned int size);
|
||||
|
||||
void registReadCallback(const std::shared_ptr<IReaderCallback>& reader);
|
||||
void unregistReadCallback(const std::shared_ptr<IReaderCallback>& reader);
|
||||
|
||||
protected:
|
||||
Ipc(const char* reader_name, const char* writer_name) noexcept;
|
||||
|
||||
private:
|
||||
void doReciver(std::weak_ptr<Ipc> wThis);
|
||||
|
||||
void onReciveer(const char* buffer, unsigned int size);
|
||||
|
||||
private:
|
||||
std::string reader_name_;
|
||||
std::string writer_name_;
|
||||
std::unique_ptr<ipc::channel> sender_;
|
||||
std::unique_ptr<ipc::channel> receiver_;
|
||||
std::thread reciver_thread_;
|
||||
std::atomic_bool reciver_stop_{false};
|
||||
|
||||
std::mutex mutex_;
|
||||
using ReaderCallbackList = std::vector<std::shared_ptr<IReaderCallback>>;
|
||||
ReaderCallbackList reader_callbacks_;
|
||||
};
|
||||
|
28
src/Ipc/IpcMoudle.cpp
Normal file
28
src/Ipc/IpcMoudle.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include "Ipc/IpcMoudle.h"
|
||||
|
||||
#include "Core/Core.h"
|
||||
#include "Ipc/ipclib.h"
|
||||
|
||||
IpcMoudle* Singleton<IpcMoudle>::instance_ = nullptr;
|
||||
|
||||
bool IpcMoudle::Initialize() {
|
||||
if (!initialize("ipc_sender", "ipc_sender")) {
|
||||
ERRORLOG("ipc initialize failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
setReaderCallback([](const char* data, unsigned int size) {
|
||||
INFOLOG("ipc recive data:{}", size);
|
||||
}
|
||||
);
|
||||
|
||||
if (!listen()) {
|
||||
ERRORLOG("ipc listen failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void IpcMoudle::Uninitialize() {
|
||||
uninitialize();
|
||||
}
|
15
src/Ipc/IpcMoudle.h
Normal file
15
src/Ipc/IpcMoudle.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "Core/Singleton.h"
|
||||
#include "Core/Constant.h"
|
||||
|
||||
class IpcMoudle : public Singleton<IpcMoudle> {
|
||||
NON_COPYABLE(IpcMoudle)
|
||||
|
||||
public:
|
||||
IpcMoudle() = default;
|
||||
virtual ~IpcMoudle() = default;
|
||||
bool Initialize() override;
|
||||
void Uninitialize() override;
|
||||
};
|
||||
|
9
src/Ipc/ReadCallback.h
Normal file
9
src/Ipc/ReadCallback.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
class IReaderCallback {
|
||||
public:
|
||||
virtual ~IReaderCallback() = default;
|
||||
|
||||
// read thread callback
|
||||
virtual void onRead(const char* buffer, unsigned int size) = 0;
|
||||
};
|
20
src/Ipc/config.h
Normal file
20
src/Ipc/config.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _IPC_EXPORT_
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#define IPC_EXPORT __declspec( dllexport )
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
#else
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#define IPC_EXPORT __declspec( dllimport )
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
#endif // _IPC_EXPORT_
|
||||
|
69
src/Ipc/ipclib.cpp
Normal file
69
src/Ipc/ipclib.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
#include "Ipc/ipclib.h"
|
||||
|
||||
#include <memory>
|
||||
#include <assert.h>
|
||||
|
||||
#include "Ipc.h"
|
||||
#include "ReadCallback.h"
|
||||
|
||||
class ReaderCallback : public IReaderCallback {
|
||||
public:
|
||||
ReaderCallback() = default;
|
||||
~ReaderCallback() override = default;
|
||||
void onRead(const char* buffer, unsigned int size) override {
|
||||
printf("%s", buffer);
|
||||
if (nullptr != m_readerCallbackFunc) {
|
||||
m_readerCallbackFunc(buffer, size);
|
||||
}
|
||||
}
|
||||
|
||||
void setCallback(ReaderCallbackFunc func) {
|
||||
m_readerCallbackFunc = func;
|
||||
}
|
||||
|
||||
private:
|
||||
ReaderCallback(const ReaderCallback&) = delete;
|
||||
ReaderCallback operator= (const ReaderCallback&) = delete;
|
||||
|
||||
private:
|
||||
ReaderCallbackFunc m_readerCallbackFunc{nullptr};
|
||||
};
|
||||
|
||||
std::shared_ptr<Ipc> g_ipc;
|
||||
std::shared_ptr<ReaderCallback> g_readCallback;
|
||||
|
||||
bool __stdcall initialize(const char* sender_name, const char* receiver_name) {
|
||||
assert(!g_ipc);
|
||||
g_ipc = Ipc::create(sender_name, receiver_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
void __stdcall uninitialize() {
|
||||
assert(g_ipc);
|
||||
g_ipc->stop();
|
||||
if (g_readCallback) {
|
||||
g_ipc->unregistReadCallback(g_readCallback);
|
||||
g_readCallback.reset();
|
||||
}
|
||||
g_ipc.reset();
|
||||
}
|
||||
|
||||
bool __stdcall listen() {
|
||||
assert(g_ipc);
|
||||
return g_ipc->listen();
|
||||
}
|
||||
|
||||
bool __stdcall send(const char* data, unsigned int size) {
|
||||
assert(g_ipc);
|
||||
return g_ipc->send(data, size);
|
||||
}
|
||||
|
||||
bool __stdcall setReaderCallback(ReaderCallbackFunc callback) {
|
||||
assert(g_ipc);
|
||||
if (!g_readCallback) {
|
||||
g_readCallback = std::make_shared<ReaderCallback>();
|
||||
g_ipc->registReadCallback(g_readCallback);
|
||||
}
|
||||
g_readCallback->setCallback(callback);
|
||||
return true;
|
||||
}
|
21
src/Ipc/ipclib.h
Normal file
21
src/Ipc/ipclib.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "Ipc/config.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
typedef void(__stdcall *ReaderCallbackFunc)(const char* data, unsigned int size);
|
||||
|
||||
IPC_EXPORT bool __stdcall initialize(const char* sender_name, const char* receiver_name);
|
||||
IPC_EXPORT void __stdcall uninitialize();
|
||||
|
||||
IPC_EXPORT bool __stdcall listen();
|
||||
IPC_EXPORT bool __stdcall send(const char* data, unsigned int size);
|
||||
IPC_EXPORT bool __stdcall setReaderCallback(ReaderCallbackFunc callback);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
181
src/Main.cpp
Normal file
181
src/Main.cpp
Normal file
@ -0,0 +1,181 @@
|
||||
#if 1
|
||||
#include <Windows.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/ext.hpp>
|
||||
#include <stb/stb_image.h>
|
||||
|
||||
#include "Core/Logger.h"
|
||||
#include "Core/ScopeLock.h"
|
||||
#include "Ipc/IpcMoudle.h"
|
||||
#include "shader_s.h"
|
||||
|
||||
|
||||
static int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) {
|
||||
Logger::Init();
|
||||
IpcMoudle::Init();
|
||||
auto glfwErrorCallback = [](int error, const char* description) {
|
||||
ERRORLOG("code={}, description={}", error, description);
|
||||
};
|
||||
|
||||
glfwSetErrorCallback(glfwErrorCallback);
|
||||
|
||||
if (GLFW_TRUE != glfwInit()) {
|
||||
return -1; //exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_SAMPLES, 4);
|
||||
if (true) {
|
||||
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
|
||||
}
|
||||
|
||||
glfwWindowHint(GLFW_RESIZABLE, true);
|
||||
glfwWindowHint(GLFW_DECORATED, true);
|
||||
glfwWindowHint(GLFW_FOCUSED, true);
|
||||
glfwWindowHint(GLFW_MAXIMIZED, false);
|
||||
glfwWindowHint(GLFW_FLOATING, false);
|
||||
glfwWindowHint(GLFW_VISIBLE, true);
|
||||
glfwWindowHint(GLFW_AUTO_ICONIFY, true);
|
||||
//glfwWindowHint(GLFW_REFRESH_RATE, settings.refreshRate);
|
||||
glfwWindowHint(GLFW_SAMPLES, 4);
|
||||
|
||||
GLFWwindow* window = glfwCreateWindow(860, 540, "humanRender", nullptr, nullptr);
|
||||
if (!window) {
|
||||
ERRORLOG("glfwCreateWindow failed");
|
||||
glfwTerminate();
|
||||
return false;
|
||||
}
|
||||
|
||||
glfwSetKeyCallback(window, [](GLFWwindow* window, int key, int scancode, int action, int mods) {
|
||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
|
||||
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
||||
}
|
||||
);
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
glewExperimental = GL_TRUE;
|
||||
GLenum err = glewInit();
|
||||
if (GLEW_OK != err) {
|
||||
const GLubyte* errorString = glewGetErrorString(err);
|
||||
ERRORLOG("glewInit={1}, err={2}", err, reinterpret_cast<const char*>(errorString));
|
||||
glfwDestroyWindow(window);
|
||||
glfwTerminate();
|
||||
return -1;
|
||||
}
|
||||
|
||||
glfwSwapInterval(1);
|
||||
|
||||
|
||||
float vertices[] = {
|
||||
// positions // colors // texture coords
|
||||
1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
|
||||
1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
|
||||
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
|
||||
-1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
|
||||
};
|
||||
unsigned int indices[] = {
|
||||
0, 1, 3, // first triangle
|
||||
1, 2, 3 // second triangle
|
||||
};
|
||||
unsigned int VBO, VAO, EBO;
|
||||
glGenVertexArrays(1, &VAO);
|
||||
glGenBuffers(1, &VBO);
|
||||
glGenBuffers(1, &EBO);
|
||||
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
|
||||
glBindVertexArray(VAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
|
||||
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3* sizeof(float)));
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
|
||||
glEnableVertexAttribArray(2);
|
||||
|
||||
// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
// remember: do NOT unbind the EBO while a VAO is active as the bound element buffer object IS stored in the VAO; keep the EBO bound.
|
||||
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
|
||||
// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
|
||||
glBindVertexArray(0);
|
||||
|
||||
unsigned int texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture); // all upcoming GL_TEXTURE_2D operations now have effect on this texture object
|
||||
// set the texture wrapping parameters
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
// set texture filtering parameters
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
// load image, create texture and generate mipmaps
|
||||
int width, height, nrChannels;
|
||||
// The FileSystem::getPath(...) is part of the GitHub repository so we can find files on any IDE/platform; replace it with your own image path.
|
||||
stbi_set_flip_vertically_on_load(true);
|
||||
unsigned char* data = stbi_load("./data/background/background.jpg", &width, &height, &nrChannels, 0);
|
||||
if (data) {
|
||||
if (nrChannels == 3) {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
|
||||
} else if (nrChannels == 4) {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
}
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
} else {
|
||||
std::cout << "Failed to load texture" << std::endl;
|
||||
}
|
||||
stbi_image_free(data);
|
||||
|
||||
Shader shader("./data/shader/texture.vs", "./data/shader/texture.fs");
|
||||
|
||||
while (!glfwWindowShouldClose(window)) {
|
||||
|
||||
float ratio;
|
||||
glm::mat4 model, view, projection, mvp;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
height = height == 0 ? 1 : height;
|
||||
|
||||
ratio = width / (float)height;
|
||||
glViewport(0, 0, width, height);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glClearColor(49.f / 255, 77.f / 255, 121.f / 255, 1.f);
|
||||
view = glm::lookAt(glm::vec3(0, 0, 10), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
|
||||
projection = glm::perspective(glm::radians(60.f), ratio, 1.f, 1000.f);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
shader.use();
|
||||
|
||||
glBindVertexArray(VAO);
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
|
||||
//glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
glfwTerminate();
|
||||
|
||||
IpcMoudle::Shotdown();
|
||||
Logger::Shotdown();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
@ -1,36 +1,36 @@
|
||||
#if 1
|
||||
#include <windows.h>
|
||||
|
||||
#include "Application/Application.h"
|
||||
|
||||
#include "Window/GLFWImpl/GLFWImpl.h"
|
||||
|
||||
static int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) {
|
||||
Application app;
|
||||
if (!app.Initialize()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
WindowSettings settings;
|
||||
GLFWImpl impl;
|
||||
if (!impl.Create(settings)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*PPEngine::Window::WindowSettings settings;
|
||||
settings.title = "PPEditor";
|
||||
PPEngine::PPRHI::DriverSettings driverSettings;
|
||||
PPEngine::Window::Window window(driverSettings, settings, std::make_unique<CFrameWnd>());*/
|
||||
//CFrameWnd* window = new CFrameWnd();
|
||||
//window->Create(NULL, "ProjectorPlayer", WNDSTYLE_FRAME, 0L, 0L, 0, 640, 480);
|
||||
//window->CenterWindow();
|
||||
//window->ShowWindow(true);
|
||||
//godot_hinstance = hInstance;
|
||||
|
||||
int ret = app.RunLoop();
|
||||
app.Uninitialize();
|
||||
return ret;
|
||||
}
|
||||
//#include <windows.h>
|
||||
//
|
||||
//#include "Application/Application.h"
|
||||
//
|
||||
//#include "Window/GLFWImpl/GLFWImpl.h"
|
||||
//
|
||||
//static int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) {
|
||||
// Application app;
|
||||
// if (!app.Initialize()) {
|
||||
// return -1;
|
||||
// }
|
||||
//
|
||||
// WindowSettings settings;
|
||||
// GLFWImpl impl;
|
||||
// if (!impl.Create(settings)) {
|
||||
// return -1;
|
||||
// }
|
||||
//
|
||||
// /*PPEngine::Window::WindowSettings settings;
|
||||
// settings.title = "PPEditor";
|
||||
// PPEngine::PPRHI::DriverSettings driverSettings;
|
||||
// PPEngine::Window::Window window(driverSettings, settings, std::make_unique<CFrameWnd>());*/
|
||||
// //CFrameWnd* window = new CFrameWnd();
|
||||
// //window->Create(NULL, "ProjectorPlayer", WNDSTYLE_FRAME, 0L, 0L, 0, 640, 480);
|
||||
// //window->CenterWindow();
|
||||
// //window->ShowWindow(true);
|
||||
// //godot_hinstance = hInstance;
|
||||
//
|
||||
// int ret = app.RunLoop();
|
||||
// app.Uninitialize();
|
||||
// return ret;
|
||||
//}
|
||||
|
||||
#else
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "Core/Core.h"
|
||||
#include "RHI/DriverSettings.h"
|
||||
#include "RHI/RHICommond.h"
|
||||
|
||||
@ -18,43 +19,43 @@ public:
|
||||
|
||||
virtual RHICommond* CreateVAOCommand(
|
||||
class Mesh* mesh,
|
||||
unsigned int vaoHandle,
|
||||
unsigned int vboHandle,
|
||||
unsigned int eboHandle
|
||||
uint32 vaoHandle,
|
||||
uint32 vboHandle,
|
||||
uint32 eboHandle
|
||||
) = 0;
|
||||
virtual RHICommond* DrawArrayCommand(
|
||||
unsigned int vaoHandle,
|
||||
unsigned int vaoStart,
|
||||
unsigned int vaoCount
|
||||
uint32 vaoHandle,
|
||||
uint32 vaoStart,
|
||||
uint32 vaoCount
|
||||
) = 0;
|
||||
virtual RHICommond* DrawElementsCommand(
|
||||
unsigned int vaoHandle,
|
||||
unsigned int eboHandle,
|
||||
unsigned int eboCount
|
||||
uint32 vaoHandle,
|
||||
uint32 eboHandle,
|
||||
uint32 eboCount
|
||||
) = 0;
|
||||
virtual RHICommond* DeleteVAOCommand(
|
||||
unsigned int vaoHandle,
|
||||
unsigned int vboHandle,
|
||||
unsigned int eboHandle
|
||||
uint32 vaoHandle,
|
||||
uint32 vboHandle,
|
||||
uint32 eboHandle
|
||||
) = 0;
|
||||
virtual RHICommond* CreateShaderCommand(
|
||||
unsigned int shaderHandle,
|
||||
unsigned int type,
|
||||
uint32 shaderHandle,
|
||||
uint32 type,
|
||||
const std::string& shader
|
||||
) = 0;
|
||||
virtual RHICommond* DeleteShaderCommand(
|
||||
unsigned int shaderHandle
|
||||
uint32 shaderHandle
|
||||
) = 0;
|
||||
virtual RHICommond* CreateProgramCommand(
|
||||
unsigned int programHandle,
|
||||
const std::vector<unsigned int>& shaders
|
||||
uint32 programHandle,
|
||||
const std::vector<uint32>& shaders
|
||||
) = 0;
|
||||
virtual RHICommond* UseProgramCommand(
|
||||
unsigned int programHandle,
|
||||
uint32 programHandle,
|
||||
bool use
|
||||
) = 0;
|
||||
virtual RHICommond* DeleteProgramCommand(
|
||||
unsigned int programHandle
|
||||
uint32 programHandle
|
||||
) = 0;
|
||||
virtual RHICommond* CreateStartCommand() = 0;
|
||||
virtual RHICommond* CreateEndCommand() = 0;
|
||||
|
@ -265,11 +265,11 @@ void GLStartCommand::OnExecute() {
|
||||
|
||||
GLEndCommand::GLEndCommand()
|
||||
: RHICommond(RHICommond::Type::END_FRAME) {
|
||||
//INFOLOG("actor {}", spdlog::fmt_lib::ptr(this));
|
||||
INFOLOG("actor {}", spdlog::fmt_lib::ptr(this));
|
||||
}
|
||||
|
||||
GLEndCommand::~GLEndCommand() {
|
||||
//INFOLOG("dctor {}", spdlog::fmt_lib::ptr(this));
|
||||
INFOLOG("dctor {}", spdlog::fmt_lib::ptr(this));
|
||||
}
|
||||
|
||||
|
||||
@ -280,3 +280,4 @@ void GLEndCommand::OnExecute() {
|
||||
}
|
||||
setting.renderSwapBuffers();
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "Renderer/MeshRender.h"
|
||||
|
||||
#include "RHI/OpenglDrv/GLHandleMapper.h"
|
||||
#include "Renderer/ShaderSoruce.h"
|
||||
|
||||
MeshRender::MeshRender(Mesh* mesh)
|
||||
: mesh_(mesh) {
|
||||
@ -16,6 +17,8 @@ MeshRender::~MeshRender() {
|
||||
RHI::Get()->Push(task);
|
||||
}
|
||||
|
||||
uint32 vsHandle = 0;
|
||||
uint32 fsHandle = 0;
|
||||
void MeshRender::Render() {
|
||||
if (nullptr == mesh_) {
|
||||
return;
|
||||
@ -27,6 +30,8 @@ void MeshRender::Render() {
|
||||
eboHandle_ = GLHandleMapper::GeneratorEBOHandle();
|
||||
auto task = rhiApi_->CreateVAOCommand(mesh_, vaoHandle_, vboHandle_, eboHandle_);
|
||||
RHI::Get()->Push(task);
|
||||
vsHandle = GLHandleMapper::GeneratorShaderHandle();
|
||||
//rhiApi_->CreateShaderCommand()
|
||||
} else {
|
||||
auto task = rhiApi_->DrawElementsCommand(vaoHandle_, eboHandle_, mesh_->GetIndexCount());
|
||||
RHI::Get()->Push(task);
|
||||
|
28
src/Renderer/ShaderSoruce.h
Normal file
28
src/Renderer/ShaderSoruce.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
//顶点着色器代码
|
||||
static const char* vertex_shader_text =
|
||||
"#version 330\n"
|
||||
|
||||
"uniform mat4 u_mvp;\n"
|
||||
|
||||
"in vec3 a_pos;\n"
|
||||
"in vec4 a_color;\n"
|
||||
|
||||
"out vec4 v_color;\n"
|
||||
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_Position = vec4(a_pos, 1.0);\n"
|
||||
" v_color = a_color;\n"
|
||||
"}\n";
|
||||
|
||||
//片段着色器代码
|
||||
static const char* fragment_shader_text =
|
||||
"#version 330\n"
|
||||
"in vec4 v_color;\n"
|
||||
"out vec4 o_fragColor;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" o_fragColor = v_color;\n"
|
||||
"}\n";
|
123
src/shader_s.h
Normal file
123
src/shader_s.h
Normal file
@ -0,0 +1,123 @@
|
||||
#ifndef SHADER_H
|
||||
#define SHADER_H
|
||||
|
||||
#define GLEW_STATIC
|
||||
#include <GL/glew.h>
|
||||
#include <glfw/glfw3.h>
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
class Shader
|
||||
{
|
||||
public:
|
||||
unsigned int ID;
|
||||
// constructor generates the shader on the fly
|
||||
// ------------------------------------------------------------------------
|
||||
Shader(const char* vertexPath, const char* fragmentPath)
|
||||
{
|
||||
// 1. retrieve the vertex/fragment source code from filePath
|
||||
std::string vertexCode;
|
||||
std::string fragmentCode;
|
||||
std::ifstream vShaderFile;
|
||||
std::ifstream fShaderFile;
|
||||
// ensure ifstream objects can throw exceptions:
|
||||
vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
|
||||
fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
|
||||
try
|
||||
{
|
||||
// open files
|
||||
vShaderFile.open(vertexPath);
|
||||
fShaderFile.open(fragmentPath);
|
||||
std::stringstream vShaderStream, fShaderStream;
|
||||
// read file's buffer contents into streams
|
||||
vShaderStream << vShaderFile.rdbuf();
|
||||
fShaderStream << fShaderFile.rdbuf();
|
||||
// close file handlers
|
||||
vShaderFile.close();
|
||||
fShaderFile.close();
|
||||
// convert stream into string
|
||||
vertexCode = vShaderStream.str();
|
||||
fragmentCode = fShaderStream.str();
|
||||
}
|
||||
catch (std::ifstream::failure& e)
|
||||
{
|
||||
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl;
|
||||
}
|
||||
const char* vShaderCode = vertexCode.c_str();
|
||||
const char * fShaderCode = fragmentCode.c_str();
|
||||
// 2. compile shaders
|
||||
unsigned int vertex, fragment;
|
||||
// vertex shader
|
||||
vertex = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vertex, 1, &vShaderCode, NULL);
|
||||
glCompileShader(vertex);
|
||||
checkCompileErrors(vertex, "VERTEX");
|
||||
// fragment Shader
|
||||
fragment = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(fragment, 1, &fShaderCode, NULL);
|
||||
glCompileShader(fragment);
|
||||
checkCompileErrors(fragment, "FRAGMENT");
|
||||
// shader Program
|
||||
ID = glCreateProgram();
|
||||
glAttachShader(ID, vertex);
|
||||
glAttachShader(ID, fragment);
|
||||
glLinkProgram(ID);
|
||||
checkCompileErrors(ID, "PROGRAM");
|
||||
// delete the shaders as they're linked into our program now and no longer necessary
|
||||
glDeleteShader(vertex);
|
||||
glDeleteShader(fragment);
|
||||
}
|
||||
// activate the shader
|
||||
// ------------------------------------------------------------------------
|
||||
void use()
|
||||
{
|
||||
glUseProgram(ID);
|
||||
}
|
||||
// utility uniform functions
|
||||
// ------------------------------------------------------------------------
|
||||
void setBool(const std::string &name, bool value) const
|
||||
{
|
||||
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void setInt(const std::string &name, int value) const
|
||||
{
|
||||
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void setFloat(const std::string &name, float value) const
|
||||
{
|
||||
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
|
||||
}
|
||||
|
||||
private:
|
||||
// utility function for checking shader compilation/linking errors.
|
||||
// ------------------------------------------------------------------------
|
||||
void checkCompileErrors(unsigned int shader, std::string type)
|
||||
{
|
||||
int success;
|
||||
char infoLog[1024];
|
||||
if (type != "PROGRAM")
|
||||
{
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||
if (!success)
|
||||
{
|
||||
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
|
||||
std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
glGetProgramiv(shader, GL_LINK_STATUS, &success);
|
||||
if (!success)
|
||||
{
|
||||
glGetProgramInfoLog(shader, 1024, NULL, infoLog);
|
||||
std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user