Update Nemirtingas overlay to latest.

This commit is contained in:
Mr_Goldberg 2022-08-05 02:06:42 -04:00
parent df94c38b0f
commit c17fb0c931
No known key found for this signature in database
GPG Key ID: 8597D87419DEF278
82 changed files with 48737 additions and 59872 deletions

View File

@ -643,6 +643,12 @@ inline bool file_exists (const std::string& name) {
return (stat (name.c_str(), &buffer) == 0); return (stat (name.c_str(), &buffer) == 0);
} }
#ifdef DETOURS_64BIT
#define DLL_NAME "steam_api64.dll"
#else
#define DLL_NAME "steam_api.dll"
#endif
HMODULE (WINAPI *Real_GetModuleHandleA)(LPCSTR lpModuleName) = GetModuleHandleA; HMODULE (WINAPI *Real_GetModuleHandleA)(LPCSTR lpModuleName) = GetModuleHandleA;
HMODULE WINAPI Mine_GetModuleHandleA(LPCSTR lpModuleName) HMODULE WINAPI Mine_GetModuleHandleA(LPCSTR lpModuleName)
{ {

View File

@ -76,12 +76,6 @@
#include <winhttp.h> #include <winhttp.h>
#include "../detours/detours.h" #include "../detours/detours.h"
#ifdef DETOURS_64BIT
#define DLL_NAME "steam_api64.dll"
#else
#define DLL_NAME "steam_api.dll"
#endif
#endif #endif
#include <string> #include <string>

28581
glew/glew.c

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,4 @@
#include "Base_Hook.h" #include "Base_Hook.h"
#include "Hook_Manager.h"
#include <algorithm> #include <algorithm>

View File

@ -1,36 +0,0 @@
#include "../dll/dll.h"
#include "Hook_Manager.h"
#ifdef EMU_OVERLAY
Hook_Manager::Hook_Manager()
{}
Hook_Manager::~Hook_Manager()
{
for (auto& i : _hooks)
delete i;
}
Hook_Manager& Hook_Manager::Inst()
{
static Hook_Manager hook;
return hook;
}
void Hook_Manager::AddHook(Base_Hook* hook)
{
_hooks.insert(hook);
}
void Hook_Manager::RemoveHook(Base_Hook* hook)
{
auto it = _hooks.find(hook);
if (it != _hooks.end())
{
delete hook;
_hooks.erase(it);
}
}
#endif//EMU_OVERLAY

View File

@ -1,27 +0,0 @@
#ifndef __INCLUDED_HOOK_BASE_H__
#define __INCLUDED_HOOK_BASE_H__
#include "Base_Hook.h"
#ifdef EMU_OVERLAY
class Hook_Manager
{
friend class Base_Hook;
protected:
std::set<Base_Hook*> _hooks;
Hook_Manager();
virtual ~Hook_Manager();
public:
static Hook_Manager& Inst();
void AddHook(Base_Hook* hook);
void RemoveHook(Base_Hook* hook);
};
#endif//EMU_OVERLAY
#endif//__INCLUDED_HOOK_BASE_H__

File diff suppressed because it is too large Load Diff

View File

@ -1,104 +1,30 @@
#ifndef __INCLUDED_RENDERER_DETECTOR_H__ /*
#define __INCLUDED_RENDERER_DETECTOR_H__ * Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "Base_Hook.h" #pragma once
#ifdef EMU_OVERLAY #include "../dll/base.h"
#ifdef __WINDOWS__
struct IDXGISwapChain; #include <future>
struct IDirect3DDevice9; #include <chrono>
struct IDirect3DDevice9Ex; #include <memory>
class Renderer_Detector #include "Renderer_Hook.h"
{
private:
// Variables
std::thread* _hook_thread;
std::mutex _found_mutex;
unsigned int _hook_retries;
bool _renderer_found; // Is the renderer hooked ?
bool _dx9_hooked;
bool _dx10_hooked;
bool _dx11_hooked;
bool _dx12_hooked;
bool _dxgi_hooked;
bool _ogl_hooked; // wglMakeCurrent is hooked ? (opengl)
Base_Hook* rendererdetect_hook;
Base_Hook* game_renderer;
ATOM atom; std::future<Renderer_Hook*> detect_renderer(std::chrono::milliseconds timeout = std::chrono::milliseconds{-1});
HWND dummy_hWnd;
// Functions
Renderer_Detector();
~Renderer_Detector();
static HRESULT STDMETHODCALLTYPE MyIDXGISwapChain_Present(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags);
static HRESULT STDMETHODCALLTYPE MyPresent(IDirect3DDevice9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion);
static HRESULT STDMETHODCALLTYPE MyPresentEx(IDirect3DDevice9Ex* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags);
static BOOL WINAPI MywglMakeCurrent(HDC hDC, HGLRC hGLRC);
void HookDXGIPresent(IDXGISwapChain* pSwapChain);
void HookDX9Present(IDirect3DDevice9* pDevice, bool ex);
void HookwglMakeCurrent(decltype(wglMakeCurrent)* wglMakeCurrent);
void hook_dx9();
void hook_dx10();
void hook_dx11();
void hook_dx12();
void hook_opengl();
void create_hwnd();
void destroy_hwnd();
void create_hook(const char* libname);
bool stop_retry();
static void find_renderer_proc(Renderer_Detector* _this);
public:
void find_renderer();
void renderer_found(Base_Hook* hook);
Base_Hook* get_renderer() const;
static Renderer_Detector& Inst();
};
#elif defined __LINUX__
#include "linux/OpenGLX_Hook.h"
class Renderer_Detector
{
// Variables
std::thread* _hook_thread;
std::mutex _found_mutex;
unsigned int _hook_retries;
bool _oglx_hooked;
bool _renderer_found; // Is the renderer hooked ?
Base_Hook* rendererdetect_hook;
Base_Hook* game_renderer;
// Functions
Renderer_Detector();
~Renderer_Detector();
static void MyglXSwapBuffers(Display *dpy, GLXDrawable drawable);
void HookglXSwapBuffers(decltype(glXSwapBuffers)* glXSwapBuffers);
void hook_openglx(const char* libname);
void create_hook(const char* libname);
bool stop_retry();
static void find_renderer_proc(Renderer_Detector* _this);
public:
void find_renderer();
void renderer_found(Base_Hook* hook);
Base_Hook* get_renderer() const;
static Renderer_Detector& Inst();
};
#endif//__WINDOWS__
#endif//EMU_OVERLAY
#endif//__INCLUDED_RENDERER_DETECTOR_H__

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <functional>
#include <string>
#include <memory>
#include <cstdint>
class Renderer_Hook
{
public:
Renderer_Hook():
OverlayProc(&DefaultOverlayProc),
OverlayHookReady(&DefaultOverlayHookReady)
{}
static void DefaultOverlayProc() {}
static void DefaultOverlayHookReady(bool) {}
std::function<void()> OverlayProc;
std::function<void(bool)> OverlayHookReady;
virtual bool StartHook(std::function<bool(bool)> key_combination_callback) = 0;
virtual bool IsStarted() = 0;
// Returns a Handle to the renderer image ressource or nullptr if it failed to create the resource, the handle can be used in ImGui's Image calls, image_buffer must be RGBA ordered
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height) = 0;
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource) = 0;
virtual std::string GetLibraryName() const = 0;
};

View File

@ -0,0 +1,116 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <type_traits>
namespace System {
template<typename Enum>
struct EnableBitMaskOperators
{
static constexpr bool enable = false;
};
template<typename T>
constexpr typename std::underlying_type<T>::type GetEnumValue(T enum_value)
{
return static_cast<typename std::underlying_type<T>::type>(enum_value);
}
}
template<typename Enum>
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type
operator |(Enum lhs, Enum rhs)
{
using underlying = typename std::underlying_type<Enum>::type;
return static_cast<Enum> (
static_cast<underlying>(lhs) |
static_cast<underlying>(rhs)
);
}
template<typename Enum>
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type
operator &(Enum lhs, Enum rhs)
{
using underlying = typename std::underlying_type<Enum>::type;
return static_cast<Enum> (
static_cast<underlying>(lhs) &
static_cast<underlying>(rhs)
);
}
template<typename Enum>
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type
operator ^(Enum lhs, Enum rhs)
{
using underlying = typename std::underlying_type<Enum>::type;
return static_cast<Enum> (
static_cast<underlying>(lhs) ^
static_cast<underlying>(rhs)
);
}
template<typename Enum>
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type
operator ~(Enum lhs)
{
using underlying = typename std::underlying_type<Enum>::type;
return static_cast<Enum> (~static_cast<underlying>(lhs));
}
template<typename Enum>
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type&
operator |=(Enum& lhs, Enum rhs)
{
lhs = lhs | rhs;
return lhs;
}
template<typename Enum>
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type&
operator &=(Enum& lhs, Enum rhs)
{
lhs = lhs & rhs;
return lhs;
}
template<typename Enum>
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, Enum>::type&
operator ^=(Enum& lhs, Enum rhs)
{
lhs = lhs ^ rhs;
return lhs;
}
template<typename Enum>
constexpr typename std::enable_if<System::EnableBitMaskOperators<Enum>::enable, bool>::type
operator !(Enum lhs)
{
using underlying = typename std::underlying_type<Enum>::type;
return !static_cast<underlying>(lhs);
}
#define UTILS_ENABLE_BITMASK_OPERATORS(T) \
template<> \
struct System::EnableBitMaskOperators<T> \
{ \
static constexpr bool enable = true; \
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstddef> // size_t
namespace System {
namespace ConstExpr {
template<typename T, size_t N>
constexpr size_t CountOf(T(&)[N])
{
return N;
}
template<typename T, size_t N>
constexpr size_t StrLen(T(&)[N])
{
return N-1;
}
// Sum of all parameter pack sizeof
template <typename... Ts>
constexpr size_t size_of = 0;
template <typename T, typename... Ts>
constexpr size_t size_of<T, Ts...> = sizeof(T) + size_of<Ts...>;
}
}

View File

@ -0,0 +1,127 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "System_internals.h"
#include "Encoding.hpp"
#include "utfcpp/utf8.h"
#include <string.h>
#include <algorithm>
namespace System {
namespace Encoding {
namespace details {
template<typename T, size_t s = sizeof(typename T::value_type)>
struct string_deducer
{
static std::string convert_string(T const& str) = delete;
static std::wstring convert_wstring(T const& str) = delete;
};
template<typename T>
struct string_deducer<T, 1>
{
static std::string convert_string(T const& str)
{
return std::string(std::begin(str), std::end(str));
}
static std::wstring convert_wstring(std::string const& str)
{
std::wstring r(std::begin(str), std::end(str));
return r;
}
};
template<typename T>
struct string_deducer<T, 2>
{
static std::string convert_string(T const& str)
{
std::string r;
utf8::utf16to8(std::begin(str), std::end(str), std::back_inserter(r));
return r;
}
static std::wstring convert_wstring(std::string const& str)
{
std::wstring r;
utf8::utf8to16(std::begin(str), std::end(str), std::back_inserter(r));
return r;
}
};
template<typename T>
struct string_deducer<T, 4>
{
static std::string convert_string(T const& str)
{
std::string r;
utf8::utf32to8(std::begin(str), std::end(str), std::back_inserter(r));
return r;
}
static std::wstring convert_wstring(std::string const& str)
{
std::wstring r;
utf8::utf8to32(std::begin(str), std::end(str), std::back_inserter(r));
return r;
}
};
}
std::wstring Utf8ToWChar(std::string const& str)
{
return details::string_deducer<std::wstring>::convert_wstring(str);
}
std::u16string Utf8ToUtf16(std::string const& str)
{
return utf8::utf8to16(str);
}
std::u32string Utf8ToUtf32(std::string const& str)
{
return utf8::utf8to32(str);
}
std::string WCharToUtf8(std::wstring const& str)
{
return details::string_deducer<std::wstring>::convert_string(str);
}
std::string Utf16ToUtf8(std::u16string const& str)
{
return utf8::utf16to8(str);
}
std::string Utf32ToUtf8(std::u32string const& str)
{
return utf8::utf32to8(str);
}
size_t EncodedLength(std::string const& str)
{
return utf8::distance(str.begin(), str.end());
}
}// namespace Encoding
}// namespace System

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
namespace System {
namespace Encoding {
std::wstring Utf8ToWChar(std::string const& str);
std::u16string Utf8ToUtf16(std::string const& str);
std::u32string Utf8ToUtf32(std::string const& str);
std::string WCharToUtf8(std::wstring const& str);
std::string Utf16ToUtf8(std::u16string const& str);
std::string Utf32ToUtf8(std::u32string const& str);
// Size of UTF8 chars (not the size of the byte buffer).
size_t EncodedLength(std::string const& str);
}
}

View File

@ -0,0 +1,128 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstddef> // size_t
#include <cstdint> // uint*_t
namespace System {
class Endian
{
private:
template<typename T, size_t byte_count>
struct ByteSwapImpl
{
constexpr static inline T swap(T v)
{
for (int i = 0; i < (byte_count/2); ++i)
{
uint8_t tmp = reinterpret_cast<uint8_t*>(&v)[i];
reinterpret_cast<uint8_t*>(&v)[i] = reinterpret_cast<uint8_t*>(&v)[byte_count - i - 1];
reinterpret_cast<uint8_t*>(&v)[byte_count - i - 1] = tmp;
}
return v;
}
};
template<typename T>
struct ByteSwapImpl<T, 1>
{
constexpr static inline T swap(T v) { return v; }
};
template<typename T>
struct ByteSwapImpl<T, 2>
{
constexpr static inline T swap(T v)
{
uint16_t& tmp = *reinterpret_cast<uint16_t*>(&v);
tmp = ((tmp & 0x00ffu) << 8)
| ((tmp & 0xff00u) >> 8);
return v;
}
};
template<typename T>
struct ByteSwapImpl<T, 4>
{
constexpr static inline T swap(T v)
{
uint32_t& tmp = *reinterpret_cast<uint32_t*>(&v);
tmp = ((tmp & 0x000000fful) << 24)
| ((tmp & 0x0000ff00ul) << 8)
| ((tmp & 0x00ff0000ul) >> 8)
| ((tmp & 0xff000000ul) >> 24);
return v;
}
};
template<typename T>
struct ByteSwapImpl<T, 8>
{
constexpr static inline T swap(T v)
{
uint64_t& tmp = *reinterpret_cast<uint64_t*>(&v);
tmp = ((tmp & 0x00000000000000ffull) << 56)
| ((tmp & 0x000000000000ff00ull) << 40)
| ((tmp & 0x0000000000ff0000ull) << 24)
| ((tmp & 0x00000000ff000000ull) << 8)
| ((tmp & 0x000000ff00000000ull) >> 8)
| ((tmp & 0x0000ff0000000000ull) >> 24)
| ((tmp & 0x00ff000000000000ull) >> 40)
| ((tmp & 0xff00000000000000ull) >> 56);
return v;
}
};
public:
static inline bool little()
{
const uint32_t endian_magic = 0x01020304;
return reinterpret_cast<const uint8_t*>(&endian_magic)[0] == 0x04;
}
static inline bool big()
{
const uint32_t endian_magic = 0x01020304;
return reinterpret_cast<const uint8_t*>(&endian_magic)[0] == 0x01;
}
template<typename T, size_t Size = sizeof(T)>
constexpr static inline T net_swap(T v)
{
if(Endian::little())
{
return ByteSwapImpl<T, Size>::swap(v);
}
return v;
}
template<typename T, size_t Size = sizeof(T)>
constexpr static inline T swap(T v)
{
return ByteSwapImpl<T, Size>::swap(v);
}
private:
Endian() = delete;
};
}

View File

@ -0,0 +1,562 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "Filesystem.h"
#include "Encoding.hpp"
#include "System_internals.h"
#if defined(SYSTEM_OS_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define NOMINMAX
#include <Windows.h>
#ifdef CreateDirectory
#undef CreateDirectory
#endif
#ifdef DeleteFile
#undef DeleteFile
#endif
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
#include <sys/types.h>
#include <sys/ioctl.h> // get iface broadcast
#include <sys/stat.h> // stats on a file (is directory, size, mtime)
#include <dirent.h> // to open directories
#include <dlfcn.h> // dlopen (like dll for linux)
#include <string.h>
#include <limits.h> // PATH_MAX
#include <unistd.h>
#else
#error "unknown arch"
#endif
#include <fstream>
#include <algorithm>
#include <iterator>
#include <ctime>
namespace System {
namespace Filesystem {
static void _CleanSlashes(std::string& str);
std::string Filename(std::string const& path)
{
size_t pos = path.find_last_of("/\\");
if (pos != std::string::npos)
return path.substr(pos+1);
return path;
}
std::string Dirname(std::string const& path)
{
std::string r(path);
_CleanSlashes(r);
size_t pos = r.find_last_of("/\\");
if (pos == std::string::npos || (pos == 0 && r.length() == 1))
return std::string();
if (pos == 0)
++pos;
return r.substr(0, pos);
}
std::string Join(StringView r, StringView l)
{
std::string result(r.to_string());
result += Separator;
result += l.to_string();
_CleanSlashes(result);
return result;
}
std::string CanonicalPath(std::string const& path)
{
if (IsAbsolute(path))
return CleanPath(path);
return CleanPath(Join(GetCwd(),path));
}
size_t FileSize(std::string const& path)
{
std::ifstream in_file(path, std::ios::in | std::ios::binary | std::ios::ate);
if (in_file)
{
return in_file.tellg();
}
return 0;
}
std::chrono::system_clock::time_point FileATime(std::string const& path)
{
struct stat file_stat = {};
if (stat(path.c_str(), &file_stat) != 0)
return std::chrono::system_clock::time_point{};
return std::chrono::system_clock::from_time_t(file_stat.st_atime);
}
std::chrono::system_clock::time_point FileMTime(std::string const& path)
{
struct stat file_stat = {};
if (stat(path.c_str(), &file_stat) != 0)
return std::chrono::system_clock::time_point{};
return std::chrono::system_clock::from_time_t(file_stat.st_mtime);
}
std::chrono::system_clock::time_point FileCTime(std::string const& path)
{
struct stat file_stat = {};
if (stat(path.c_str(), &file_stat) != 0)
return std::chrono::system_clock::time_point{};
return std::chrono::system_clock::from_time_t(file_stat.st_ctime);
}
#ifdef SYSTEM_OS_WINDOWS
static void _CleanSlashes(std::string& str)
{
size_t pos;
std::replace(str.begin(), str.end(), '/', '\\');
while ((pos = str.find("\\\\")) != std::string::npos)
str.replace(pos, 2, "\\");
pos = 0;
while ((pos = str.find("\\.", pos)) != std::string::npos)
{
if (str[pos + 2] == '\\' || (pos + 2) >= str.length())
{
str.replace(pos, 3, "\\");
}
else
{
++pos;
}
}
}
std::string GetCwd()
{
DWORD size = GetCurrentDirectoryW(0, nullptr);
if (size == 0)
return ".";
std::wstring wdirectory;
++size;
wdirectory.resize(size);
wdirectory.resize(GetCurrentDirectoryW(size, &wdirectory[0]));
wdirectory += L'\\';
return System::Encoding::WCharToUtf8(wdirectory);
}
bool IsAbsolute(std::string const& path)
{
return path.length() >= 2 && (((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z')) && path[1] == ':');
}
std::string CleanPath(std::string const& path)
{
std::string cleaned_path(path);
size_t pos;
size_t size;
_CleanSlashes(cleaned_path);
pos = 0;
while ((pos = cleaned_path.find("\\..", pos)) != std::string::npos )
{
if (cleaned_path[pos + 3] == '\\' || (pos+3) >= cleaned_path.length())
{
if (pos == 0)
size = 3;
else
{
size_t parent_pos = cleaned_path.rfind("\\", pos - 1);
if (parent_pos == std::string::npos)
{
size = pos + 3;
pos = 0;
}
else
{
size = 3 + pos - parent_pos;
pos = parent_pos;
}
}
cleaned_path.replace(pos, size, "");
}
else
{
++pos;
}
}
return cleaned_path;
}
bool IsDir(std::string const& path)
{
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
DWORD attrs = GetFileAttributesW(wpath.c_str());
return attrs != INVALID_FILE_ATTRIBUTES && attrs & FILE_ATTRIBUTE_DIRECTORY;
}
bool IsFile(std::string const& path)
{
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
DWORD attrs = GetFileAttributesW(wpath.c_str());
return attrs != INVALID_FILE_ATTRIBUTES && ((attrs & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY);
}
bool Exists(std::string const& path)
{
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
DWORD attrs = GetFileAttributesW(wpath.c_str());
return attrs != INVALID_FILE_ATTRIBUTES;
}
bool CreateDirectory(std::string const& directory, bool recursive)
{
size_t pos = 0;
struct _stat sb;
std::wstring sub_dir;
std::wstring wdirectory(System::Encoding::Utf8ToWChar(directory));
if (wdirectory.empty())
return false;
if (recursive)
{
pos = 3;
do
{
pos = wdirectory.find_first_of(L"\\/", pos + 1);
sub_dir = std::move(wdirectory.substr(0, pos));
if (_wstat(sub_dir.c_str(), &sb) == 0)
{
if (!(sb.st_mode & _S_IFDIR))
{// A subpath in the target is not a directory
return false;
}
// Folder Exists
}
else if (CreateDirectoryW(wdirectory.substr(0, pos).c_str(), NULL) == FALSE && GetLastError() != ERROR_ALREADY_EXISTS)
{// Failed to create directory
return false;
}
}
while (pos != std::string::npos);
return true;
}
return (CreateDirectoryW(wdirectory.c_str(), NULL) != FALSE || GetLastError() == ERROR_ALREADY_EXISTS);
}
bool DeleteFile(std::string const& path)
{
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
return DeleteFileW(wpath.c_str()) == TRUE || GetLastError() == ERROR_FILE_NOT_FOUND;
}
static std::vector<std::wstring> ListFiles(std::wstring const& path, bool files_only, bool recursive)
{
std::vector<std::wstring> files;
WIN32_FIND_DATAW hfind_data;
HANDLE hfind = INVALID_HANDLE_VALUE;
std::wstring search_path = path;
if (*path.rbegin() != L'\\')
search_path += L'\\';
search_path += L'*';
// Start iterating over the files in the path directory.
hfind = FindFirstFileW(search_path.c_str(), &hfind_data);
if (hfind != INVALID_HANDLE_VALUE)
{
search_path.pop_back();
do // Managed to locate and create an handle to that folder.
{
if (wcscmp(L".", hfind_data.cFileName) == 0
|| wcscmp(L"..", hfind_data.cFileName) == 0)
continue;
if (hfind_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (recursive)
{
std::wstring dir_name = hfind_data.cFileName;
std::vector<std::wstring> sub_files = std::move(ListFiles(search_path + dir_name, files_only, true));
std::transform(sub_files.begin(), sub_files.end(), std::back_inserter(files), [&dir_name](std::wstring& Filename)
{
return dir_name + L'\\' + Filename;
});
}
if (!files_only)
{
files.emplace_back(hfind_data.cFileName);
}
}
else
{
files.emplace_back(hfind_data.cFileName);
}
} while (FindNextFileW(hfind, &hfind_data) == TRUE);
FindClose(hfind);
}
return files;
}
std::vector<std::string> ListFiles(std::string const& path, bool files_only, bool recursive)
{
std::vector<std::string> files;
std::wstring wpath(System::Encoding::Utf8ToWChar(path));
std::vector<std::wstring> wfiles(std::move(ListFiles(wpath, files_only, recursive)));
files.reserve(wfiles.size());
std::transform(wfiles.begin(), wfiles.end(), std::back_inserter(files), [](std::wstring const& wFilename)
{
return System::Encoding::WCharToUtf8(wFilename);
});
return files;
}
#else
static void _CleanSlashes(std::string& str)
{
size_t pos;
std::replace(str.begin(), str.end(), '\\', '/');
while ((pos = str.find("//")) != std::string::npos)
str.replace(pos, 2, "/");
pos = 0;
while ((pos = str.find("/.", pos)) != std::string::npos)
{
if (str[pos + 2] == '/' || (pos + 2) >= str.length())
{
str.replace(pos, 3, "/");
}
else
{
++pos;
}
}
}
std::string GetCwd()
{
char buff[4096];
std::string tmp(getcwd(buff, 4096) == nullptr ? "." : buff);
tmp += '/';
return tmp;
}
bool IsAbsolute(std::string const& path)
{
return path[0] == '/';
}
std::string CleanPath(std::string const& path)
{
std::string cleaned_path(path);
size_t pos;
size_t size;
std::replace(cleaned_path.begin(), cleaned_path.end(), '\\', '/');
_CleanSlashes(cleaned_path);
pos = 0;
while ((pos = cleaned_path.find("/..", pos)) != std::string::npos)
{
if (cleaned_path[pos + 3] == '/' || (pos + 3) >= cleaned_path.length())
{
if (pos == 0)
size = 3;
else
{
size_t parent_pos = cleaned_path.rfind("/", pos - 1);
if (parent_pos == std::string::npos)
{
size = pos + 3;
pos = 0;
}
else
{
size = 3 + pos - parent_pos;
pos = parent_pos;
}
}
cleaned_path.replace(pos, size, "");
}
else
{
++pos;
}
}
return cleaned_path;
}
bool IsDir(std::string const& path)
{
struct stat sb;
if (stat(path.c_str(), &sb) == 0)
{
return S_ISDIR(sb.st_mode);
}
return false;
}
bool IsFile(std::string const& path)
{
struct stat sb;
if (stat(path.c_str(), &sb) == 0)
{
return S_ISREG(sb.st_mode);
}
return false;
}
bool Exists(std::string const& path)
{
struct stat sb;
return stat(path.c_str(), &sb) == 0;
}
bool CreateDirectory(std::string const& directory, bool recursive)
{
size_t pos = 0;
struct stat sb;
std::string sub_dir;
do
{
pos = directory.find("/", pos + 1);
sub_dir = std::move(directory.substr(0, pos));
if (stat(sub_dir.c_str(), &sb) == 0)
{
if (!S_ISDIR(sb.st_mode))
{// A subpath in the target is not a directory
return false;
}
// Folder Exists
}
else if (mkdir(sub_dir.c_str(), 0755) < 0 && errno != EEXIST)
{// Failed to create directory (no permission?)
return false;
}
}
while (pos != std::string::npos);
return true;
}
bool DeleteFile(std::string const& path)
{
return unlink(path.c_str()) == 0;
}
std::vector<std::string> ListFiles(std::string const& path, bool files_only, bool recursive)
{
std::vector<std::string> files;
std::string search_path = path;
if (*path.rbegin() != Separator)
search_path += Separator;
DIR* dir = opendir(search_path.c_str());
struct dirent* entry;
if (dir == nullptr)
return files;
while ((entry = readdir(dir)) != nullptr)
{
if (strcmp(entry->d_name, ".") == 0
|| strcmp(entry->d_name, "..") == 0)
continue;
if (entry->d_type == DT_DIR)
{
if (recursive)
{
std::string dir_name = entry->d_name;
std::vector<std::string> sub_files = std::move(ListFiles(search_path + dir_name, true));
std::transform(sub_files.begin(), sub_files.end(), std::back_inserter(files), [&dir_name](std::string& Filename)
{
return dir_name + Separator + Filename;
});
}
if (!files_only)
{
files.emplace_back(entry->d_name);
}
}
else if (entry->d_type == DT_REG)
{
files.emplace_back(entry->d_name);
}
}
closedir(dir);
return files;
}
#endif
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
#include <vector>
#include <chrono>
#include "StringView.hpp"
#ifdef CreateDirectory
#undef CreateDirectory
#endif
#ifdef DeleteFile
#undef DeleteFile
#endif
namespace System {
namespace Filesystem {
constexpr static char WindowsSeparator = '\\';
constexpr static char UnixSeparator = '/';
#if defined(WIN64) || defined(_WIN64) || defined(__MINGW64__) || defined(WIN32) || defined(_WIN32) || defined(__MINGW32__)
constexpr static char Separator = WindowsSeparator;
#else
constexpr static char Separator = UnixSeparator;
#endif
std::string CleanPath(std::string const& path);
std::string Filename(std::string const& path);
std::string Dirname(std::string const& path);
bool IsAbsolute(std::string const& path);
inline std::string Join(StringView s) { return s.to_string(); }
std::string Join(StringView r, StringView l);
template<typename ...Args>
std::string Join(StringView path, Args&& ...args)
{
return Join(path, StringView(Join(args...)));
}
std::string GetCwd();
std::string CanonicalPath(std::string const& path);
bool IsDir(std::string const& path);
bool IsFile(std::string const& path);
bool Exists(std::string const& path);
size_t FileSize(std::string const& path);
std::chrono::system_clock::time_point FileATime(std::string const& path);
std::chrono::system_clock::time_point FileMTime(std::string const& path);
std::chrono::system_clock::time_point FileCTime(std::string const& path);
bool CreateDirectory(std::string const& folder, bool recursive = true);
bool DeleteFile(std::string const& path);
std::vector<std::string> ListFiles(std::string const& path, bool files_only, bool recursive = false);
}
}

View File

@ -0,0 +1,418 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "Library.h"
#include "Encoding.hpp"
#include "System_internals.h"
#include <memory>
#if defined(SYSTEM_OS_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define NOMINMAX
#include <Windows.h>
constexpr char library_suffix[] = ".dll";
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
#include <dlfcn.h>
#include <cstring>
#if defined(SYSTEM_OS_LINUX)
#include <dirent.h> // to open directories
#include <unistd.h>
constexpr char library_suffix[] = ".so";
#else
#include <mach-o/dyld_images.h>
constexpr char library_suffix[] = ".dylib";
#endif
#endif
namespace System {
namespace Library {
#if defined(SYSTEM_OS_WINDOWS)
void* OpenLibrary(const char* library_name)
{
if (library_name == nullptr)
return nullptr;
std::wstring wide(System::Encoding::Utf8ToWChar(library_name));
return LoadLibraryW(wide.c_str());
}
void CloseLibrary(void* handle)
{
if(handle != nullptr)
FreeLibrary((HMODULE)handle);
}
void* GetSymbol(void* handle, const char* symbol_name)
{
if (symbol_name == nullptr)
return nullptr;
return GetProcAddress((HMODULE)handle, symbol_name);
}
void* GetLibraryHandle(const char* library_name)
{
if (library_name == nullptr)
return nullptr;
std::wstring wide(System::Encoding::Utf8ToWChar(library_name));
return GetModuleHandleW(wide.c_str());
}
std::string GetLibraryPath(void* handle)
{
if (handle == nullptr)
return std::string();
std::wstring wpath(1024, L'\0');
DWORD size;
while ((size = GetModuleFileNameW((HMODULE)handle, &wpath[0], wpath.length())) == wpath.length())
{
wpath.resize(wpath.length() * 2);
}
wpath.resize(size);
return System::Encoding::WCharToUtf8(wpath);
}
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
void* OpenLibrary(const char* library_name)
{
if (library_name == nullptr)
return nullptr;
return dlopen(library_name, RTLD_NOW);
}
void CloseLibrary(void* handle)
{
if(handle != nullptr)
dlclose(handle);
}
void* GetSymbol(void* handle, const char* symbol_name)
{
if (handle == nullptr)
return nullptr;
return dlsym(handle, symbol_name);
}
#if defined(SYSTEM_OS_LINUX)
std::string GetLibraryPath(void* handle)
{
if (handle == nullptr)
return std::string();
std::string const self("/proc/self/map_files/");
DIR* dir;
struct dirent* dir_entry;
std::string file_path;
std::string res;
dir = opendir(self.c_str());
if (dir != nullptr)
{
while ((dir_entry = readdir(dir)) != nullptr)
{
file_path = (self + dir_entry->d_name);
if (dir_entry->d_type != DT_LNK)
{// Not a link
continue;
}
file_path = System::ExpandSymlink(file_path);
void* lib_handle = dlopen(file_path.c_str(), RTLD_NOW);
if (lib_handle != nullptr)
{// Don't increment ref_counter.
dlclose(lib_handle);
if (handle == lib_handle)
{
res = std::move(file_path);
break;
}
}
}
closedir(dir);
}
return res;
}
void* GetLibraryHandle(const char* library_name)
{
if (library_name == nullptr)
return nullptr;
std::string const self("/proc/self/map_files/");
DIR* dir;
struct dirent* dir_entry;
void* res = nullptr;
size_t library_name_len = strlen(library_name);
dir = opendir(self.c_str());
if (dir != nullptr)
{
std::string file_path;
while ((dir_entry = readdir(dir)) != nullptr)
{
file_path = (self + dir_entry->d_name);
if (dir_entry->d_type != DT_LNK)
{// Not a link
continue;
}
file_path = System::ExpandSymlink(file_path);
auto pos = file_path.rfind('/');
if (pos != std::string::npos)
{
++pos;
if (strncmp(file_path.c_str() + pos, library_name, library_name_len) == 0)
{
res = dlopen(file_path.c_str(), RTLD_NOW);
if (res != nullptr)
{// Like Windows' GetModuleHandle, we don't want to increment the ref counter
dlclose(res);
}
break;
}
}
}
closedir(dir);
}
return res;
}
#else
std::string GetLibraryPath(void* handle)
{
if (handle == nullptr)
return std::string();
task_dyld_info dyld_info;
task_t t;
pid_t pid = getpid();
task_for_pid(mach_task_self(), pid, &t);
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
{
dyld_all_image_infos* dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
{
void* res = dlopen(dyld_img_infos->infoArray[i].imageFilePath, RTLD_NOW);
if (res != nullptr)
{
dlclose(res);
if(res == handle)
return std::string(dyld_img_infos->infoArray[i].imageFilePath);
}
}
}
return std::string();
}
void* GetLibraryHandle(const char* library_name)
{
if (library_name == nullptr)
return nullptr;
void* res = nullptr;
size_t library_name_len = strlen(library_name);
task_dyld_info dyld_info;
task_t t;
pid_t pid = getpid();
task_for_pid(mach_task_self(), pid, &t);
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
{
const char* pos;
dyld_all_image_infos* dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
{
pos = strrchr(dyld_img_infos->infoArray[i].imageFilePath, '/');
if (pos != nullptr)
{
++pos;
if (strncmp(pos, library_name, library_name_len) == 0)
{
res = dlopen(dyld_img_infos->infoArray[i].imageFilePath, RTLD_NOW);
if (res != nullptr)
{// Like Windows' GetModuleHandle, we don't want to increment the ref counter
dlclose(res);
}
break;
}
}
}
}
return res;
}
#endif
#endif
std::string GetLibraryExtension()
{
return std::string{ library_suffix };
}
class LibraryImpl
{
std::shared_ptr<void> _Handle;
struct LibraryHandleDestructor
{
void operator()(void* h)
{
System::Library::CloseLibrary(h);
}
};
public:
inline bool OpenLibrary(std::string const& library_name, bool append_extension)
{
std::string lib_name = (append_extension ? library_name + library_suffix : library_name);
void* lib = System::Library::OpenLibrary(lib_name.c_str());
if (lib == nullptr)
{
lib_name = "lib" + lib_name;
lib = System::Library::OpenLibrary(lib_name.c_str());
if (lib == nullptr)
return false;
}
_Handle = std::shared_ptr<void>(lib, LibraryHandleDestructor());
return true;
}
inline void CloseLibrary()
{
_Handle.reset();
}
inline void* GetVSymbol(std::string const& symbol_name) const
{
return System::Library::GetSymbol(_Handle.get(), symbol_name.c_str());
}
inline std::string GetLibraryPath() const
{
return System::Library::GetLibraryPath(_Handle.get());
}
inline void* GetLibraryNativeHandle() const
{
return _Handle.get();
}
inline bool IsLoaded() const
{
return _Handle != nullptr;
}
};
Library::Library():
_Impl(new LibraryImpl)
{}
Library::Library(Library const& other):
_Impl(new LibraryImpl(*other._Impl))
{}
Library::Library(Library&& other) noexcept:
_Impl(other._Impl)
{
other._Impl = nullptr;
}
Library& Library::operator=(Library const& other)
{
*_Impl = *other._Impl;
return *this;
}
Library& Library::operator=(Library&& other) noexcept
{
std::swap(_Impl, other._Impl);
return *this;
}
Library::~Library()
{
delete _Impl; _Impl = nullptr;
}
bool Library::OpenLibrary(std::string const& library_name, bool append_extension)
{
return _Impl->OpenLibrary(library_name, append_extension);
}
void Library::CloseLibrary()
{
_Impl->CloseLibrary();
}
void* Library::GetVSymbol(std::string const& symbol_name) const
{
return _Impl->GetVSymbol(symbol_name);
}
std::string Library::GetLibraryPath() const
{
return _Impl->GetLibraryPath();
}
void* Library::GetLibraryNativeHandle() const
{
return _Impl->GetLibraryNativeHandle();
}
bool Library::IsLoaded() const
{
return _Impl->IsLoaded();
}
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
namespace System {
namespace Library {
class Library
{
class LibraryImpl* _Impl;
public:
Library();
Library(Library const& other);
Library(Library&& other) noexcept;
Library& operator=(Library const& other);
Library& operator=(Library&& other) noexcept;
~Library();
bool OpenLibrary(std::string const& library_name, bool append_extension);
void CloseLibrary();
void* GetVSymbol(std::string const& symbol_name) const;
template<typename T>
inline T* GetSymbol(std::string const& symbol_name) const
{
return reinterpret_cast<T*>(GetVSymbol(symbol_name));
}
std::string GetLibraryPath() const;
void* GetLibraryNativeHandle() const;
bool IsLoaded() const;
};
// Triies to load the library, I suggest that you use a Library instance instead
void* OpenLibrary(const char* library_name);
// Will decrease the OS' ref counter on the library, use it to close a handle opened by open_library.
// A Library instance will automatically call this in the destructor
void CloseLibrary(void* handle);
// Will try to retrieve a symbol address from the library handle
void* GetSymbol(void* handle, const char* symbol_name);
// Get a pointer to the library, if it is not loaded, will return nullptr. This doesn't increment the OS' internal ref counter
void* GetLibraryHandle(const char* library_name);
// Get the library path of a module handle
std::string GetLibraryPath(void* handle);
// Get the native extension representing a shared library.
std::string GetLibraryExtension();
}
}

View File

@ -0,0 +1,96 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <tuple>
#include <mutex>
namespace System {
class scoped_lock {
struct value_holder
{
virtual ~value_holder() noexcept {}
};
template<typename... Args>
struct templated_value_holder : value_holder
{
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type unlock(std::tuple<Tp...>& t) { }
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type unlock(std::tuple<Tp...>& t)
{
std::get<I>(t).unlock();
unlock<I + 1, Tp...>(t);
}
explicit templated_value_holder(Args&... mutexes) : _mutexes(mutexes...) { std::lock(mutexes...); }
explicit templated_value_holder(std::adopt_lock_t, Args&... mutexes) : _mutexes(mutexes...) {} // construct but don't lock
virtual ~templated_value_holder() noexcept { unlock(_mutexes); }
std::tuple<Args&...> _mutexes;
};
template<typename Arg>
struct templated_value_holder<Arg> : value_holder
{
explicit templated_value_holder(Arg& mutex) : _mutex(mutex) { _mutex.lock(); }
explicit templated_value_holder(std::adopt_lock_t, Arg& mutex) : _mutex(mutex) {} // construct but don't lock
virtual ~templated_value_holder() noexcept { _mutex.unlock(); }
Arg& _mutex;
};
value_holder* _val;
public:
template<typename... Args>
explicit scoped_lock(Args&... mutexes) : _val(new templated_value_holder<Args&...>(mutexes...)) { }
template<typename... Args>
explicit scoped_lock(std::adopt_lock_t, Args&... mutexes) : _val(new templated_value_holder<Args&...>(std::adopt_lock, mutexes...)) { }
explicit scoped_lock(scoped_lock && other):
_val(other._val)
{
other._val = nullptr;
}
scoped_lock() noexcept:
_val(nullptr)
{}
~scoped_lock() noexcept { delete _val; }
scoped_lock& operator=(scoped_lock && other)
{
_val = other._val;
other._val = nullptr;
return *this;
}
scoped_lock(const scoped_lock&) = delete;
scoped_lock& operator=(const scoped_lock&) = delete;
};
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "System_internals.h"
#include "String.hpp"
#include <string.h>
#include <algorithm>
#include <cctype>
namespace System {
namespace String {
namespace details {
void LeftTrim(std::string& str)
{
str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](const char c)
{
return !std::isspace((unsigned char)c);
}));
}
void RightTrim(std::string& str)
{
str.erase(std::find_if(str.rbegin(), str.rend(), [](const char c)
{
return !std::isspace((unsigned char)c);
}).base(), str.end());
}
void ToUpper(char* str, size_t len)
{
while(len--)
{
unsigned char c = (unsigned char)*str;
*str++ = std::toupper(c);
}
}
void ToLower(char* str, size_t len)
{
while (len--)
{
unsigned char c = (unsigned char)*str;
*str++ = std::tolower(c);
}
}
char* CloneString(System::StringView src)
{
size_t len = src.length() + 1;
char* res = new char[len];
memcpy(res, src.data(), len);
return res;
}
size_t CopyString(System::StringView src, char* dst, size_t dst_size)
{
size_t written = 0;
if (dst != nullptr && dst_size > 0)
{
written = src.length() > dst_size ? dst_size - 1 : src.length();
memcpy(dst, src.data(), written);
dst[written] = '\0';
}
return written;
}
}// namespace details
}// namespace String
}// namespace System

View File

@ -0,0 +1,290 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
#include <cstdint>
#include <cstring>
#include <iterator>
#include "StringView.hpp"
#include "StringSwitch.hpp"
namespace System {
namespace String {
///////////////////////////////////////////////////////////
// Implementations
namespace details {
void LeftTrim(std::string& str);
void RightTrim(std::string& str);
void ToUpper(char* str, size_t len);
void ToLower(char* str, size_t len);
char* CloneString(System::StringView src);
size_t CopyString(System::StringView src, char *dst, size_t dst_size);
}
inline void LeftTrim(std::string& str)
{
details::LeftTrim(str);
}
inline void RightTrim(std::string& str)
{
details::RightTrim(str);
}
inline void Trim(std::string& str)
{
LeftTrim(str);
RightTrim(str);
}
inline std::string CopyLeftTrim(const char* str)
{
if (str == nullptr)
return std::string();
std::string r(str);
LeftTrim(r);
return r;
}
inline std::string CopyLeftTrim(System::StringView str)
{
std::string r(str.to_string());
LeftTrim(r);
return r;
}
inline std::string CopyLeftTrim(std::string const& str)
{
std::string r(str);
LeftTrim(r);
return r;
}
inline std::string CopyRightTrim(const char* str)
{
if (str == nullptr)
return std::string();
std::string r(str);
RightTrim(r);
return r;
}
inline std::string CopyRightTrim(System::StringView str)
{
std::string r(str.to_string());
RightTrim(r);
return r;
}
inline std::string CopyRightTrim(std::string const& str)
{
std::string r(str);
RightTrim(r);
return r;
}
inline std::string CopyTrim(const char* str)
{
if (str == nullptr)
return std::string();
std::string r(str);
Trim(r);
return r;
}
inline std::string CopyTrim(System::StringView str)
{
std::string r(str.to_string());
Trim(r);
return r;
}
inline std::string CopyTrim(std::string const& str)
{
std::string r(str);
Trim(r);
return r;
}
inline void ToLower(std::string& str)
{
details::ToLower(&str[0], str.length());
}
inline void ToLower(char* str)
{
if (str == nullptr)
return;
details::ToLower(str, strlen(str));
}
inline std::string CopyLower(std::string const& str)
{
std::string r(str);
details::ToLower(&r[0], r.length());
return r;
}
inline std::string CopyLower(const char* str)
{
std::string r(str == nullptr ? "" : str);
details::ToLower(&r[0], r.length());
return r;
}
inline std::string CopyLower(System::StringView str)
{
std::string r = str.to_string();
details::ToLower(&r[0], r.length());
return r;
}
inline void ToUpper(std::string& str)
{
details::ToUpper(&str[0], str.length());
}
inline void ToUpper(char* str)
{
if (str == nullptr)
return;
details::ToUpper(str, strlen(str));
}
inline std::string CopyUpper(std::string const& str)
{
std::string r(str);
details::ToUpper(&r[0], r.length());
return r;
}
inline std::string CopyUpper(const char* str)
{
std::string r(str == nullptr ? "" : str);
details::ToUpper(&r[0], r.length());
return r;
}
inline std::string CopyUpper(System::StringView str)
{
std::string r = str.to_string();
details::ToUpper(&r[0], r.length());
return r;
}
template<typename IteratorType>
inline std::string Join(IteratorType begin, IteratorType end, const std::string& sep)
{
std::string res;
if (begin != end)
res = *begin++;
while (begin != end)
{
res += sep;
res += *begin++;
}
return res;
}
template<typename T>
inline std::string Join(T const& container, const std::string& sep)
{
return Join(std::begin(container), std::end(container), sep);
}
// Clone a string allocated with the "new" operator, if str is nullptr, an empty string ("") will be returned, NOT nullptr !
inline char* CloneString(const char* str)
{
if (str == nullptr)
return details::CloneString(System::StringView(""));
return details::CloneString(System::StringView(str, strlen(str)));
}
inline char* CloneString(std::string const& str)
{
return details::CloneString(System::StringView(str));
}
inline char* CloneString(System::StringView str)
{
return details::CloneString(str);
}
// Will always end the C-String with a null char.
inline size_t CopyString(const char* src, char* dst, size_t dst_size)
{
if (src == nullptr)
return details::CopyString(System::StringView(""), dst, dst_size);
return details::CopyString(System::StringView(src, strlen(src)), dst, dst_size);
}
inline size_t CopyString(System::StringView src, char* dst, size_t dst_size)
{
return details::CopyString(src, dst, dst_size);
}
inline size_t CopyString(std::string const& src, char* dst, size_t dst_size)
{
return details::CopyString(System::StringView(src), dst, dst_size);
}
template<size_t N>
inline size_t CopyString(const char* src, char(&dst)[N])
{
if (src == nullptr)
return details::CopyString(System::StringView(""), dst, N);
return details::CopyString(System::StringView(src, strlen(src)), dst, N);
}
template<size_t N>
inline size_t CopyString(System::StringView src, char(&dst)[N])
{
return details::CopyString(src, dst, N);
}
template<size_t N>
inline size_t CopyString(std::string const& src, char(&dst)[N])
{
return details::CopyString(System::StringView(src), dst, N);
}
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstdint>
#include <string>
#include "SystemDetector.h"
#include "StringView.hpp"
namespace System {
namespace StringSwitch {
#if defined(SYSTEM_ARCH_X86)
using hash_type = uint32_t;
#else
using hash_type = uint64_t;
#endif
namespace Detail {
constexpr char lower_char(char c) { return ((c >= 'A' && c <= 'Z') ? c + 32 : c); }
}
// switch case on a string
constexpr hash_type Hash(const char* input, size_t len) { return (len > 0 ? static_cast<hash_type>(*input) + 33 * Hash(input + 1, len - 1) : 5381); }
template<size_t N>
constexpr hash_type Hash(const char(&input)[N]) { return Hash(input, N-1); }
constexpr hash_type Hash(System::StringView sv) { return Hash(sv.data(), sv.length()); }
inline hash_type Hash(const std::string& input) { return Hash(input.c_str(), input.length()); }
constexpr hash_type IHash(const char* input, size_t len) { return (len > 0 ? static_cast<hash_type>(Detail::lower_char(*input)) + 33 * IHash(input + 1, len - 1) : 5381); }
template<size_t N>
constexpr inline hash_type IHash(const char(&input)[N]) { return IHash(input, N - 1); }
constexpr hash_type IHash(System::StringView sv) { return IHash(sv.data(), sv.length()); }
inline hash_type IHash(const std::string& input) { return IHash(input.c_str(), input.length()); }
}
}

View File

@ -0,0 +1,256 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <iterator>
#include <string>
#include <iostream>
#include <array>
namespace System {
template<typename char_type>
class BasicStringView {
const char_type* _string;
size_t _length;
using type = BasicStringView<char_type>;
public:
class iterator {
const char_type* _value;
public:
constexpr iterator(const iterator& o) : _value(o._value) {}
constexpr iterator(const char_type* value) : _value(value) {}
constexpr iterator& operator++() { ++_value; return *this; }
constexpr iterator operator++(int) { iterator retval = *this; ++(*this); return retval; }
constexpr iterator& operator--() { --_value; return *this; }
constexpr iterator operator--(int) { iterator retval = *this; --(*this); return retval; }
constexpr bool operator==(iterator other) const { return _value == other._value; }
constexpr bool operator!=(iterator other) const { return !(*this == other); }
constexpr const char_type& operator*() const { return *_value; }
// iterator traits
using difference_type = long;
using value_type = char_type;
using pointer = const char_type*;
using reference = const char_type&;
using iterator_category = std::random_access_iterator_tag;
};
constexpr BasicStringView() : _string(nullptr), _length(0)
{}
constexpr BasicStringView(const char_type* str, size_t length) : _string(str), _length(length)
{}
constexpr BasicStringView(std::basic_string<char_type, std::char_traits<char_type>, std::allocator<char_type>> const& str) : _string(str.data()), _length(str.length())
{}
template<size_t N>
constexpr BasicStringView(const char_type(&str)[N]) : _string(str), _length(N - 1)
{}
template<size_t N>
constexpr BasicStringView(std::array<char_type, N> const& str) : _string(&str.at[0]), _length(N)
{}
constexpr BasicStringView(type const& other) : _string(other._string), _length(other._length)
{}
constexpr BasicStringView(type&& other) : _string(other._string), _length(other._length)
{}
constexpr type& operator=(type const& other)
{
_string = other._string;
_length = other._length;
return *this;
}
constexpr type& operator=(type&& other)
{
_string = other._string;
_length = other._length;
return *this;
}
constexpr const char_type* data() const { return _string; }
constexpr bool empty() const { return _length == 0; }
constexpr size_t size() const { return _length; }
constexpr size_t length() const { return _length; }
constexpr const char_type& operator[](size_t index) const { return _string[index]; }
constexpr size_t find_first_of(type const& string, const size_t offset = 0) const
{
if(_length == 0)
return std::string::npos;
for (size_t i = offset; i < _length; ++i)
{
for (size_t j = 0; j < string._length; ++j)
{
if (_string[i] == string[j])
return i;
}
}
return std::string::npos;
}
constexpr size_t find_first_not_of(type const& string, const size_t offset = 0) const
{
if(_length == 0)
return std::string::npos;
for (size_t i = offset; i < _length; ++i)
{
for (size_t j = 0; j < string._length; ++j)
{
if (_string[i] == string[j])
break;
if (j == (string._length - 1))
return i;
}
}
return std::string::npos;
}
constexpr size_t find(type const& string, const size_t offset = 0) const
{
if (_length < string._length)
return std::string::npos;
for (size_t i = offset; i < (_length - string._length + 1); ++i)
{
for (size_t j = 0; j < string._length; ++j)
{
if (_string[i + j] != string[j])
break;
if (j == (string._length - 1))
return i;
}
}
return std::string::npos;
}
constexpr size_t find_not(type const& string, const size_t offset = 0) const
{
if (_length < string._length)
return std::string::npos;
for (size_t i = offset; i < (_length - string._length + 1); ++i)
{
for (size_t j = 0; j < string._length; ++j)
{
if (_string[i + j] == string[j])
break;
if (j == (string._length - 1))
return i;
}
}
return std::string::npos;
}
constexpr size_t count(char_type const c) const
{
size_t n = 0;
for (size_t i = 0; i < _length; ++i)
if (_string[i] == c)
++n;
return n;
}
constexpr type substr(size_t offset, size_t length = std::string::npos) const
{
if (offset >= _length)
return type();
return type(_string + offset, (_length - offset) > length ? length : _length - offset);
}
constexpr iterator begin() const
{
return iterator(_string);
}
constexpr iterator end() const
{
return iterator(_string + _length);
}
std::string to_string() const
{
return std::string(_string, _string + _length);
}
size_t copy(char_type* p, size_t p_size) const
{
size_t written = 0;
if (p != nullptr)
{
size_t to_write = (_length > p_size ? p_size : _length);
char_type* b = _string;
while (to_write--)
{
*p++ = *b++;
++written;
}
}
return written;
}
};
using StringView = BasicStringView<char>;
}
template<typename char_type>
std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& os, System::BasicStringView<char_type> const& sv)
{
return os.write(sv.data(), sv.length());
}
template<typename char_type>
std::basic_string<char_type> operator+(std::basic_string<char_type> const& str, System::BasicStringView<char_type> const& sv)
{
std::string r(str);
return r.append(sv.data(), sv.data() + sv.length());
}
template<typename char_type>
std::basic_string<char_type>& operator+=(std::basic_string<char_type>& str, System::BasicStringView<char_type> const& sv)
{
return str.append(sv.data(), sv.data() + sv.length());
}

View File

@ -0,0 +1,593 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "System.h"
#include "Filesystem.h"
#include "Encoding.hpp"
#include "System_internals.h"
#if defined(SYSTEM_OS_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define NOMINMAX
#include <Windows.h>
#include <TlHelp32.h>
#include <shellapi.h>
#include <shlobj.h> // (shell32.lib) Infos about current user folders
inline bool handle_is_valid(HANDLE h)
{
return (h != (HANDLE)0 && h != (HANDLE)-1);
}
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
#if defined(SYSTEM_OS_LINUX)
#include <sys/sysinfo.h> // Get uptime (second resolution)
#include <dirent.h>
#else
#include <sys/sysctl.h>
#include <mach-o/dyld_images.h>
#endif
#include <sys/types.h>
#include <pwd.h>
#include <unistd.h>
#include <dlfcn.h>
#else
#error "unknown arch"
#endif
#include <fstream>
namespace System {
std::chrono::microseconds GetUpTime()
{
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now() - GetBootTime());
}
}
namespace System {
#if defined(SYSTEM_OS_WINDOWS)
std::chrono::system_clock::time_point GetBootTime()
{
static std::chrono::system_clock::time_point boottime(std::chrono::system_clock::now() - std::chrono::milliseconds(GetTickCount64()));
return boottime;
}
std::vector<std::string> GetProcArgs()
{
std::vector<std::string> res;
LPWSTR* szArglist;
int nArgs;
szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
res.reserve(nArgs);
for (int i = 0; i < nArgs; ++i)
{
res.emplace_back(System::Encoding::WCharToUtf8(szArglist[i]));
}
LocalFree(szArglist);
return res;
}
std::string GetEnvVar(std::string const& var)
{
std::wstring wide(System::Encoding::Utf8ToWChar(var));
std::wstring wVar;
DWORD size = GetEnvironmentVariableW(wide.c_str(), nullptr, 0);
// Size can be 0, and the size includes the null char, so resize to size - 1
if (size < 2)
return std::string();
wVar.resize(size - 1);
GetEnvironmentVariableW(wide.c_str(), &wVar[0], size);
return System::Encoding::WCharToUtf8(wVar);
}
std::string GetUserdataPath()
{
WCHAR szPath[4096] = {};
HRESULT hr = SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, szPath);
if (FAILED(hr))
return std::string();
return System::Encoding::WCharToUtf8(std::wstring(szPath));
}
std::string GetExecutablePath()
{
std::string path;
std::wstring wpath(4096, L'\0');
wpath.resize(GetModuleFileNameW(nullptr, &wpath[0], wpath.length()));
return System::Encoding::WCharToUtf8(wpath);
}
std::string GetModulePath()
{
std::string path;
std::wstring wpath(4096, L'\0');
HMODULE hModule;
if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)&GetModulePath, &hModule) != FALSE)
{
DWORD size = GetModuleFileNameW((HINSTANCE)hModule, &wpath[0], wpath.length());
wpath.resize(size);
}
return System::Encoding::WCharToUtf8(wpath);
}
std::vector<std::string> GetModules()
{
std::vector<std::string> paths;
std::wstring wpath;
DWORD size;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetProcessId(GetCurrentProcess()));
if (handle_is_valid(hSnap))
{
MODULEENTRY32W entry{};
entry.dwSize = sizeof(entry);
if (Module32FirstW(hSnap, &entry) != FALSE)
{
wpath.resize(4096);
size = GetModuleFileNameW((HINSTANCE)entry.hModule, &wpath[0], wpath.length());
wpath.resize(size);
paths.emplace_back(System::Encoding::WCharToUtf8(wpath));
while (Module32NextW(hSnap, &entry) != FALSE)
{
wpath.resize(4096);
size = GetModuleFileNameW((HINSTANCE)entry.hModule, &wpath[0], wpath.length());
wpath.resize(size);
paths.emplace_back(System::Encoding::WCharToUtf8(wpath));
}
}
CloseHandle(hSnap);
}
return paths;
}
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
#ifdef SYSTEM_OS_LINUX
std::chrono::system_clock::time_point GetBootTime()
{
static std::chrono::system_clock::time_point boottime(std::chrono::seconds(0));
if (boottime == std::chrono::system_clock::time_point{})
{
std::ifstream uptime_file("/proc/uptime");
double uptime;
if (uptime_file)
{// Get uptime (millisecond resolution)
uptime_file >> uptime;
uptime_file.close();
}
else
{// If we can't open /proc/uptime, fallback to sysinfo (second resolution)
struct sysinfo infos;
if (sysinfo(&infos) != 0)
return boottime;
uptime = infos.uptime;
}
std::chrono::system_clock::time_point now_tp = std::chrono::system_clock::now();
std::chrono::system_clock::time_point uptime_tp(std::chrono::milliseconds(static_cast<uint64_t>(uptime * 1000)));
boottime = std::chrono::system_clock::time_point(now_tp - uptime_tp);
}
return boottime;
}
std::string GetExecutablePath()
{
std::string exec_path("./");
char link[2048] = {};
if (readlink("/proc/self/exe", link, sizeof(link)) > 0)
{
exec_path = link;
}
return exec_path;
}
std::string GetModulePath()
{
std::string const self("/proc/self/map_files/");
DIR* dir;
struct dirent* dir_entry;
std::string file_path;
std::string res;
uint64_t handle = (uint64_t)&GetModulePath;
uint64_t low, high;
char* tmp;
dir = opendir(self.c_str());
if (dir != nullptr)
{
while ((dir_entry = readdir(dir)) != nullptr)
{
file_path = dir_entry->d_name;
if (dir_entry->d_type != DT_LNK)
{// Not a link
continue;
}
tmp = &file_path[0];
low = strtoull(tmp, &tmp, 16);
if ((tmp - file_path.c_str()) < file_path.length())
{
high = strtoull(tmp+1, nullptr, 16);
if (low != 0 && high > low && low <= handle && handle <= high)
{
res = System::ExpandSymlink(self + file_path);
break;
}
}
}
closedir(dir);
}
return res;
}
std::vector<std::string> GetModules()
{
std::string const self("/proc/self/map_files/");
std::vector<std::string> paths;
DIR* dir;
struct dirent* dir_entry;
std::string path;
bool found;
dir = opendir(self.c_str());
if (dir != nullptr)
{
while ((dir_entry = readdir(dir)) != nullptr)
{
if (dir_entry->d_type != DT_LNK)
{// Not a link
continue;
}
found = false;
path = System::ExpandSymlink(self + dir_entry->d_name);
for (auto const& item : paths)
{
if (item == path)
{
found = true;
break;
}
}
if (!found)
paths.emplace_back(std::move(path));
}
closedir(dir);
}
return paths;
}
std::vector<std::string> GetProcArgs()
{
std::vector<std::string> res;
std::ifstream fcmdline("/proc/self/cmdline", std::ios::in | std::ios::binary);
if (fcmdline)
{
for (std::string line; std::getline(fcmdline, line, '\0');)
{
res.emplace_back(std::move(line));
}
}
return res;
}
#else
static int IsProcessTranslated()
{
int ret = 0;
size_t size = sizeof(ret);
// Call the sysctl and if successful return the result
if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) != -1)
return ret;
// If "sysctl.proc_translated" is not present then must be native
if (errno == ENOENT)
return 0;
return -1;
}
std::chrono::system_clock::time_point GetBootTime()
{
static std::chrono::system_clock::time_point boottime{};
if (boottime == std::chrono::system_clock::time_point{})
{
struct timeval boottime_tv;
size_t len = sizeof(boottime_tv);
int mib[2] = { CTL_KERN, KERN_BOOTTIME };
if (sysctl(mib, sizeof(mib)/sizeof(*mib), &boottime_tv, &len, nullptr, 0) < 0)
return boottime;
boottime = std::chrono::system_clock::time_point(
std::chrono::seconds(boottime_tv.tv_sec) +
std::chrono::microseconds(boottime_tv.tv_usec));
}
return boottime;
}
std::string GetExecutablePath()
{
std::string exec_path("./");
task_dyld_info dyld_info;
task_t t;
pid_t pid = getpid();
task_for_pid(mach_task_self(), pid, &t);
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
{
dyld_all_image_infos *dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
if (IsProcessTranslated() == 1)
{
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
{
exec_path = dyld_img_infos->infoArray[i].imageFilePath;
if (strcasestr(exec_path.c_str(), "rosetta") != nullptr)
continue;
// In case of a translated process (Rosetta maybe ?), the executable path is not the first entry.
size_t pos;
while ((pos = exec_path.find("/./")) != std::string::npos)
{
exec_path.replace(pos, 3, "/");
}
break;
}
}
else
{
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
{
// For now I don't know how to be sure to get the executable path
// but looks like the 1st entry is the executable path
exec_path = dyld_img_infos->infoArray[i].imageFilePath;
size_t pos;
while ((pos = exec_path.find("/./")) != std::string::npos)
{
exec_path.replace(pos, 3, "/");
}
break;
}
}
}
return exec_path;
}
// Workaround for MacOS, I don't know how to get module path from address.
SYSTEM_EXPORT_API(SYSTEM_EXTERN_C, void, SYSTEM_MODE_EXPORT, SYSTEM_CALL_DEFAULT) GetModulePathPlaceholder() {}
std::string GetModulePath()
{
task_dyld_info dyld_info;
task_t t;
pid_t pid = getpid();
task_for_pid(mach_task_self(), pid, &t);
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
{
dyld_all_image_infos* dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
{
void* res = dlopen(dyld_img_infos->infoArray[i].imageFilePath, RTLD_NOW);
if (res != nullptr)
{
void* placeholder = dlsym(res, "GetModulePathPlaceholder");
dlclose(res);
if(placeholder == (void*)&GetModulePathPlaceholder)
{
std::string res(dyld_img_infos->infoArray[i].imageFilePath);
size_t pos;
while((pos = res.find("/./")) != std::string::npos)
{
res.replace(pos, 3, "/");
}
return res;
}
}
}
}
return std::string();
}
std::vector<std::string> GetModules()
{
std::vector<std::string> paths;
std::string path;
size_t pos;
task_dyld_info dyld_info;
task_t t;
pid_t pid = getpid();
task_for_pid(mach_task_self(), pid, &t);
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
if (task_info(t, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS)
{
dyld_all_image_infos* dyld_img_infos = reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
for (int i = 0; i < dyld_img_infos->infoArrayCount; ++i)
{
path = dyld_img_infos->infoArray[i].imageFilePath;
while ((pos = path.find("/./")) != std::string::npos)
{
path.replace(pos, 3, "/");
}
paths.emplace_back(std::move(path));
}
}
return paths;
}
std::vector<std::string> GetProcArgs()
{
std::vector<std::string> res;
int mib[3];
int argmax;
size_t size;
int nargs;
mib[0] = CTL_KERN;
mib[1] = KERN_ARGMAX;
size = sizeof(argmax);
if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1)
{
return res;
}
std::unique_ptr<char[]> procargs(new char[argmax]);
if (procargs == nullptr)
{
return res;
}
mib[0] = CTL_KERN;
mib[1] = KERN_PROCARGS2;
mib[2] = getpid();
size = (size_t)argmax;
if (sysctl(mib, 3, procargs.get(), &size, NULL, 0) == -1)
{
return res;
}
memcpy(&nargs, procargs.get(), sizeof(nargs));
if (nargs <= 0)
{
return res;
}
char* args_end = procargs.get() + size;
char* arg_iterator = procargs.get() + sizeof(nargs);
// Skip saved exec path
while (*arg_iterator != '\0' && arg_iterator < args_end)
{
++arg_iterator;
}
// Skip trailing(s) '\0'
while (*arg_iterator == '\0' && arg_iterator < args_end)
{
++arg_iterator;
}
res.reserve(nargs);
char* arg = arg_iterator;
for (int i = 0; i < nargs && arg_iterator < args_end; ++arg_iterator)
{
if (*arg_iterator == '\0')
{
++i;
res.emplace_back(arg);
arg = arg_iterator + 1;
}
}
return res;
}
#endif
std::string GetUserdataPath()
{
std::string user_appdata_path;
/*
~/Library/Application Support/<application name>
~/Library/Preferences/<application name>
~/Library/<application name>/
*/
struct passwd* user_entry = getpwuid(getuid());
if (user_entry == nullptr || user_entry->pw_dir == nullptr)
{
char* env_var = getenv("HOME");
if (env_var != nullptr)
{
user_appdata_path = env_var;
}
}
else
{
user_appdata_path = user_entry->pw_dir;
}
if (!user_appdata_path.empty())
{
#ifdef SYSTEM_OS_LINUX
user_appdata_path = System::Filesystem::Join(user_appdata_path, ".config");
#else
user_appdata_path = System::Filesystem::Join(user_appdata_path, "Library", "Application Support");
#endif
}
return user_appdata_path;
}
std::string GetEnvVar(std::string const& var)
{
char* env = getenv(var.c_str());
if (env == nullptr)
return std::string();
return env;
}
#endif
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <chrono>
#include <string>
#include <vector>
namespace System {
std::chrono::system_clock::time_point GetBootTime();
std::chrono::microseconds GetUpTime();
// Get the current process argv
std::vector<std::string> GetProcArgs();
// Get User env variable
std::string GetEnvVar(std::string const& var);
// User appdata full path
std::string GetUserdataPath();
// Executable full path
std::string GetExecutablePath();
// .dll, .so or .dylib full path
std::string GetModulePath();
// List all loaded modules
std::vector<std::string> GetModules();
}

View File

@ -0,0 +1,105 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#if defined(WIN64) || defined(_WIN64) || defined(__MINGW64__) || defined(WIN32) || defined(_WIN32) || defined(__MINGW32__)
#define SYSTEM_OS_WINDOWS
#if defined(_M_IX86)
#define SYSTEM_ARCH_X86
#elif defined(_M_AMD64)
#define SYSTEM_ARCH_X64
#elif defined(_M_ARM)
#define SYSTEM_ARCH_ARM
#elif defined(_M_ARM64)
#define SYSTEM_ARCH_ARM64
#else
#error "Unhandled arch"
#endif
#elif defined(__linux__) || defined(linux)
#define SYSTEM_OS_LINUX
#if defined(__i386__) || defined(__i386) || defined(i386)
#define SYSTEM_ARCH_X86
#elif defined(__x86_64__) || defined(__x86_64) || defined(__amd64) || defined(__amd64__)
#define SYSTEM_ARCH_X64
#elif defined(__arm__)
#define SYSTEM_ARCH_ARM
#elif defined(__aarch64__)
#define SYSTEM_ARCH_ARM64
#else
#error "Unhandled arch"
#endif
#elif defined(__APPLE__)
#define SYSTEM_OS_APPLE
#if defined(__i386__) || defined(__i386) || defined(i386)
#define SYSTEM_ARCH_X86
#elif defined(__x86_64__) || defined(__x86_64) || defined(__amd64) || defined(__amd64__)
#define SYSTEM_ARCH_X64
#elif defined(__arm__)
#define SYSTEM_ARCH_ARM
#elif defined(__aarch64__)
#define SYSTEM_ARCH_ARM64
#else
#error "Unhandled arch"
#endif
#else
//#error "Unknown OS"
#endif
#ifdef __cplusplus
// Some constexpr for C++17 constexpr if.
namespace System {
enum class OperatingSystem {
Windows = 0,
Linux = 1,
Apple = 2,
};
enum class Arch {
x86 = 0,
x64 = 1,
arm = 2,
aarch64 = 3,
};
static constexpr OperatingSystem os =
#if defined(SYSTEM_OS_WINDOWS)
OperatingSystem::Windows;
#elif defined(SYSTEM_OS_LINUX)
OperatingSystem::Linux;
#elif defined(SYSTEM_OS_APPLE)
OperatingSystem::Apple;
#endif
static constexpr Arch arch =
#if defined(SYSTEM_ARCH_X86)
Arch::x86;
#elif defined(SYSTEM_ARCH_X64)
Arch::x64;
#elif defined(SYSTEM_ARCH_ARM)
Arch::arm;
#elif defined(SYSTEM_ARCH_ARM64)
Arch::aarch64;
#endif
}
#endif

View File

@ -0,0 +1,125 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "SystemDetector.h"
#ifdef __cplusplus
#define SYSTEM_EXTERN_NONE
#define SYSTEM_EXTERN_C extern "C"
#define SYSTEM_EXTERN_CXX extern
#else
#define SYSTEM_EXTERN_NONE
#define SYSTEM_EXTERN_C extern
#define SYSTEM_EXTERN_CXX #error "No C++ export in C"
#endif
#if defined(SYSTEM_OS_WINDOWS)
#if defined(__clang__)
#define SYSTEM_CALL_DEFAULT
#define SYSTEM_CALL_STDL __stdcall
#define SYSTEM_CALL_CDECL __cdecl
#define SYSTEM_CALL_FAST __fastcall
#define SYSTEM_CALL_THIS __thiscall
#define SYSTEM_MODE_DEFAULT
#define SYSTEM_MODE_EXPORT __declspec(dllexport)
#define SYSTEM_MODE_IMPORT __declspec(dllimport)
#define SYSTEM_MODE_HIDDEN
#define SYSTEM_HIDE_CLASS(keyword) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN keyword
#define SYSTEM_HIDE_API(return_type, call_convention) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN return_type call_convention
#define SYSTEM_EXPORT_API(extern_type, return_type, mode, call_convention) extern_type mode return_type call_convention
#else
#define SYSTEM_CALL_DEFAULT
#define SYSTEM_CALL_STDL __stdcall
#define SYSTEM_CALL_CDECL __cdecl
#define SYSTEM_CALL_FAST __fastcall
#define SYSTEM_CALL_THIS __thiscall
#define SYSTEM_MODE_DEFAULT
#define SYSTEM_MODE_EXPORT __declspec(dllexport)
#define SYSTEM_MODE_IMPORT __declspec(dllimport)
#define SYSTEM_MODE_HIDDEN
#define SYSTEM_HIDE_CLASS(keyword) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN keyword
#define SYSTEM_HIDE_API(return_type, call_convention) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN return_type call_convention
#define SYSTEM_EXPORT_API(extern_type, return_type, mode, call_convention) extern_type mode return_type call_convention
#endif
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
#define SYSTEM_CALL_DEFAULT
#define SYSTEM_CALL_STD __attribute__((stdcall))
#define SYSTEM_CALL_CDECL __attribute__((cdecl))
#define SYSTEM_CALL_FAST __attribute__((fastcall))
#define SYSTEM_CALL_THIS __attribute__((thiscall))
#define SYSTEM_MODE_DEFAULT
#define SYSTEM_MODE_EXPORT __attribute__((visibility("default")))
#define SYSTEM_MODE_IMPORT __attribute__((visibility("default")))
#define SYSTEM_MODE_HIDDEN __attribute__((visibility("hidden")))
#define SYSTEM_HIDE_CLASS(keyword) SYSTEM_EXTERN_NONE keyword SYSTEM_MODE_HIDDEN
#define SYSTEM_HIDE_API(return_type, call_convention) SYSTEM_EXTERN_NONE SYSTEM_MODE_HIDDEN return_type call_convention
#define SYSTEM_EXPORT_API(extern_type, return_type, mode, call_convention) extern_type mode return_type call_convention
//#define LOCAL_API __attribute__((visibility ("internal")))
#endif
/*
Copy/Paste this code in some source file if you want to call a function when the shared_library is loaded/unloaded.
#if defined(SYSTEM_OS_WINDOWS)
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
shared_library_load();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
shared_library_unload();
break;
}
return TRUE;
}
#elif defined(SYSTEM_OS_LINUX) || defined(SYSTEM_OS_APPLE)
__attribute__((constructor)) SYSTEM_HIDE_API(void, SYSTEM_CALL_DEFAULT) system_shared_library_constructor()
{
shared_library_load();
}
__attribute__((destructor)) SYSTEM_HIDE_API(void, SYSTEM_CALL_DEFAULT) system_shared_library_destructor()
{
shared_library_unload();
}
#endif
*/

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "System_internals.h"
#if defined(SYSTEM_OS_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define NOMINMAX
#include <Windows.h>
namespace System {
}
#elif defined(SYSTEM_OS_LINUX)
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
namespace System {
SYSTEM_HIDE_API(std::string, SYSTEM_CALL_DEFAULT) ExpandSymlink(std::string file_path)
{
struct stat file_stat;
std::string link_target;
ssize_t name_len = 128;
while(lstat(file_path.c_str(), &file_stat) >= 0 && S_ISLNK(file_stat.st_mode) == 1)
{
do
{
name_len *= 2;
link_target.resize(name_len);
name_len = readlink(file_path.c_str(), &link_target[0], link_target.length());
} while (name_len == link_target.length());
link_target.resize(name_len);
file_path = std::move(link_target);
}
return file_path;
}
}
#endif

View File

@ -0,0 +1,37 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "SystemExports.h"
#if defined(SYSTEM_OS_WINDOWS)
#include <string>
namespace System {
}
#elif defined(SYSTEM_OS_LINUX)
#include <string>
namespace System {
SYSTEM_HIDE_API(std::string , SYSTEM_CALL_DEFAULT) ExpandSymlink(std::string file_path);
}
#endif

View File

@ -0,0 +1,164 @@
/*
* Copyright (C) Nemirtingas
* This file is part of System.
*
* System is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* System is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the System; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <atomic>
#include <condition_variable>
#include <functional>
#include <future>
#include <memory>
#include <mutex>
#include <queue>
#include <thread>
#include <type_traits>
#include <vector>
namespace System {
class ThreadPool
{
using task_t = std::function<void()>;
std::atomic<bool> _StopWorkers;
std::atomic<std::size_t> _ActiveCount;
std::condition_variable _WorkerNotifier;
std::mutex _Mutex;
std::vector<std::thread> _Workers;
std::queue<task_t> _Tasks;
public:
explicit ThreadPool():
_ActiveCount(0)
{
}
~ThreadPool()
{
Join();
}
ThreadPool(ThreadPool const &) = delete;
ThreadPool(ThreadPool&&) = default;
ThreadPool&operator=(ThreadPool const &) = delete;
ThreadPool&operator=(ThreadPool&&) = default;
template <class Func, class... Args>
auto Push(Func &&fn, Args &&...args)
{
using return_type = typename std::result_of<Func(Args...)>::type;
auto task{ std::make_shared<std::packaged_task<return_type()>>(
std::bind(std::forward<Func>(fn), std::forward<Args>(args)...)
) };
auto future{ task->get_future() };
{
std::lock_guard<std::mutex> lock(_Mutex);
_Tasks.emplace([task]()
{
(*task)();
});
}
_WorkerNotifier.notify_one();
return future;
}
// Remove all pending tasks from the queue
void Clear()
{
std::lock_guard<std::mutex> lock(_Mutex);
_Tasks = {};
}
// Stops all previous and creates new worker threads.
void Start(std::size_t worker_count = std::thread::hardware_concurrency())
{
Join();
_StopWorkers = false;
for (std::size_t i = 0; i < worker_count; ++i)
_Workers.emplace_back(std::bind(&ThreadPool::_WorkerLoop, this));
}
// Wait all workers to finish
void Join()
{
_StopWorkers = true;
_WorkerNotifier.notify_all();
for (auto &thread : _Workers)
{
if (thread.joinable())
thread.join();
}
_Workers.clear();
}
std::size_t WorkerCount() const
{
return _Workers.size();
}
// Get the number of active workers
std::size_t ActiveCount() const
{
return _ActiveCount;
}
private:
void _WorkerLoop()
{
while (true)
{
auto task{ _NextTask() };
if (task)
{
++_ActiveCount;
task();
--_ActiveCount;
}
else if (_StopWorkers)
{
break;
}
}
}
task_t _NextTask()
{
std::unique_lock<std::mutex> lock{ _Mutex };
_WorkerNotifier.wait(lock, [this]() { return !_Tasks.empty() || _StopWorkers; });
if (_Tasks.empty())
return {};
auto task{ _Tasks.front() };
_Tasks.pop();
return task;
}
};
}

View File

@ -0,0 +1,34 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include "utf8/checked.h"
#include "utf8/unchecked.h"
#endif // header guard

View File

@ -0,0 +1,336 @@
// Copyright 2006-2016 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include "core.h"
#include <stdexcept>
namespace utf8
{
// Base for the exceptions that may be thrown from the library
class exception : public ::std::exception {
};
// Exceptions that may be thrown from the library functions.
class invalid_code_point : public exception {
uint32_t cp;
public:
invalid_code_point(uint32_t codepoint) : cp(codepoint) {}
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid code point"; }
uint32_t code_point() const {return cp;}
};
class invalid_utf8 : public exception {
uint8_t u8;
public:
invalid_utf8 (uint8_t u) : u8(u) {}
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-8"; }
uint8_t utf8_octet() const {return u8;}
};
class invalid_utf16 : public exception {
uint16_t u16;
public:
invalid_utf16 (uint16_t u) : u16(u) {}
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-16"; }
uint16_t utf16_word() const {return u16;}
};
class not_enough_room : public exception {
public:
virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Not enough space"; }
};
/// The library API - functions intended to be called by the users
template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result)
{
if (!utf8::internal::is_code_point_valid(cp))
throw invalid_code_point(cp);
if (cp < 0x80) // one octet
*(result++) = static_cast<uint8_t>(cp);
else if (cp < 0x800) { // two octets
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else if (cp < 0x10000) { // three octets
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else { // four octets
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
return result;
}
template <typename octet_iterator, typename output_iterator>
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
{
while (start != end) {
octet_iterator sequence_start = start;
internal::utf_error err_code = utf8::internal::validate_next(start, end);
switch (err_code) {
case internal::UTF8_OK :
for (octet_iterator it = sequence_start; it != start; ++it)
*out++ = *it;
break;
case internal::NOT_ENOUGH_ROOM:
out = utf8::append (replacement, out);
start = end;
break;
case internal::INVALID_LEAD:
out = utf8::append (replacement, out);
++start;
break;
case internal::INCOMPLETE_SEQUENCE:
case internal::OVERLONG_SEQUENCE:
case internal::INVALID_CODE_POINT:
out = utf8::append (replacement, out);
++start;
// just one replacement mark for the sequence
while (start != end && utf8::internal::is_trail(*start))
++start;
break;
}
}
return out;
}
template <typename octet_iterator, typename output_iterator>
inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
{
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
return utf8::replace_invalid(start, end, out, replacement_marker);
}
template <typename octet_iterator>
uint32_t next(octet_iterator& it, octet_iterator end)
{
uint32_t cp = 0;
internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
switch (err_code) {
case internal::UTF8_OK :
break;
case internal::NOT_ENOUGH_ROOM :
throw not_enough_room();
case internal::INVALID_LEAD :
case internal::INCOMPLETE_SEQUENCE :
case internal::OVERLONG_SEQUENCE :
throw invalid_utf8(*it);
case internal::INVALID_CODE_POINT :
throw invalid_code_point(cp);
}
return cp;
}
template <typename octet_iterator>
uint32_t peek_next(octet_iterator it, octet_iterator end)
{
return utf8::next(it, end);
}
template <typename octet_iterator>
uint32_t prior(octet_iterator& it, octet_iterator start)
{
// can't do much if it == start
if (it == start)
throw not_enough_room();
octet_iterator end = it;
// Go back until we hit either a lead octet or start
while (utf8::internal::is_trail(*(--it)))
if (it == start)
throw invalid_utf8(*it); // error - no lead byte in the sequence
return utf8::peek_next(it, end);
}
template <typename octet_iterator, typename distance_type>
void advance (octet_iterator& it, distance_type n, octet_iterator end)
{
const distance_type zero(0);
if (n < zero) {
// backward
for (distance_type i = n; i < zero; ++i)
utf8::prior(it, end);
} else {
// forward
for (distance_type i = zero; i < n; ++i)
utf8::next(it, end);
}
}
template <typename octet_iterator>
typename std::iterator_traits<octet_iterator>::difference_type
distance (octet_iterator first, octet_iterator last)
{
typename std::iterator_traits<octet_iterator>::difference_type dist;
for (dist = 0; first < last; ++dist)
utf8::next(first, last);
return dist;
}
template <typename u16bit_iterator, typename octet_iterator>
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
{
while (start != end) {
uint32_t cp = utf8::internal::mask16(*start++);
// Take care of surrogate pairs first
if (utf8::internal::is_lead_surrogate(cp)) {
if (start != end) {
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
if (utf8::internal::is_trail_surrogate(trail_surrogate))
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
else
throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
}
else
throw invalid_utf16(static_cast<uint16_t>(cp));
}
// Lone trail surrogate
else if (utf8::internal::is_trail_surrogate(cp))
throw invalid_utf16(static_cast<uint16_t>(cp));
result = utf8::append(cp, result);
}
return result;
}
template <typename u16bit_iterator, typename octet_iterator>
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
{
while (start < end) {
uint32_t cp = utf8::next(start, end);
if (cp > 0xffff) { //make a surrogate pair
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
}
else
*result++ = static_cast<uint16_t>(cp);
}
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
{
while (start != end)
result = utf8::append(*(start++), result);
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
{
while (start < end)
(*result++) = utf8::next(start, end);
return result;
}
// The iterator class
template <typename octet_iterator>
class iterator {
octet_iterator it;
octet_iterator range_start;
octet_iterator range_end;
public:
typedef uint32_t value_type;
typedef uint32_t* pointer;
typedef uint32_t& reference;
typedef std::ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
iterator () {}
explicit iterator (const octet_iterator& octet_it,
const octet_iterator& rangestart,
const octet_iterator& rangeend) :
it(octet_it), range_start(rangestart), range_end(rangeend)
{
if (it < range_start || it > range_end)
throw std::out_of_range("Invalid utf-8 iterator position");
}
// the default "big three" are OK
octet_iterator base () const { return it; }
uint32_t operator * () const
{
octet_iterator temp = it;
return utf8::next(temp, range_end);
}
bool operator == (const iterator& rhs) const
{
if (range_start != rhs.range_start || range_end != rhs.range_end)
throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
return (it == rhs.it);
}
bool operator != (const iterator& rhs) const
{
return !(operator == (rhs));
}
iterator& operator ++ ()
{
utf8::next(it, range_end);
return *this;
}
iterator operator ++ (int)
{
iterator temp = *this;
utf8::next(it, range_end);
return temp;
}
iterator& operator -- ()
{
utf8::prior(it, range_start);
return *this;
}
iterator operator -- (int)
{
iterator temp = *this;
utf8::prior(it, range_start);
return temp;
}
}; // class iterator
} // namespace utf8
#if UTF_CPP_CPLUSPLUS >= 201703L // C++ 17 or later
#include "cpp17.h"
//#elif UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later
#else
#include "cpp11.h"
#endif // C++ 11 or later
#endif //header guard

View File

@ -0,0 +1,338 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include <iterator>
// Determine the C++ standard version.
// If the user defines UTF_CPP_CPLUSPLUS, use that.
// Otherwise, trust the unreliable predefined macro __cplusplus
#if !defined UTF_CPP_CPLUSPLUS
#define UTF_CPP_CPLUSPLUS __cplusplus
#endif
#if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later
#define UTF_CPP_OVERRIDE override
#define UTF_CPP_NOEXCEPT noexcept
#else // C++ 98/03
#define UTF_CPP_OVERRIDE
#define UTF_CPP_NOEXCEPT throw()
#endif // C++ 11 or later
namespace utf8
{
// The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
// You may need to change them to match your system.
// These typedefs have the same names as ones from cstdint, or boost/cstdint
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
// Helper code - not intended to be directly called by the library users. May be changed at any time
namespace internal
{
// Unicode constants
// Leading (high) surrogates: 0xd800 - 0xdbff
// Trailing (low) surrogates: 0xdc00 - 0xdfff
const uint16_t LEAD_SURROGATE_MIN = 0xd800u;
const uint16_t LEAD_SURROGATE_MAX = 0xdbffu;
const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
const uint16_t LEAD_OFFSET = 0xd7c0u; // LEAD_SURROGATE_MIN - (0x10000 >> 10)
const uint32_t SURROGATE_OFFSET = 0xfca02400u; // 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN
// Maximum valid value for a Unicode code point
const uint32_t CODE_POINT_MAX = 0x0010ffffu;
template<typename octet_type>
inline uint8_t mask8(octet_type oc)
{
return static_cast<uint8_t>(0xff & oc);
}
template<typename u16_type>
inline uint16_t mask16(u16_type oc)
{
return static_cast<uint16_t>(0xffff & oc);
}
template<typename octet_type>
inline bool is_trail(octet_type oc)
{
return ((utf8::internal::mask8(oc) >> 6) == 0x2);
}
template <typename u16>
inline bool is_lead_surrogate(u16 cp)
{
return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
}
template <typename u16>
inline bool is_trail_surrogate(u16 cp)
{
return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
}
template <typename u16>
inline bool is_surrogate(u16 cp)
{
return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
}
template <typename u32>
inline bool is_code_point_valid(u32 cp)
{
return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
}
template <typename octet_iterator>
inline typename std::iterator_traits<octet_iterator>::difference_type
sequence_length(octet_iterator lead_it)
{
uint8_t lead = utf8::internal::mask8(*lead_it);
if (lead < 0x80)
return 1;
else if ((lead >> 5) == 0x6)
return 2;
else if ((lead >> 4) == 0xe)
return 3;
else if ((lead >> 3) == 0x1e)
return 4;
else
return 0;
}
template <typename octet_difference_type>
inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
{
if (cp < 0x80) {
if (length != 1)
return true;
}
else if (cp < 0x800) {
if (length != 2)
return true;
}
else if (cp < 0x10000) {
if (length != 3)
return true;
}
return false;
}
enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
/// Helper for get_sequence_x
template <typename octet_iterator>
utf_error increase_safely(octet_iterator& it, octet_iterator end)
{
if (++it == end)
return NOT_ENOUGH_ROOM;
if (!utf8::internal::is_trail(*it))
return INCOMPLETE_SEQUENCE;
return UTF8_OK;
}
#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
/// get_sequence_x functions decode utf-8 sequences of the length x
template <typename octet_iterator>
utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (*it) & 0x3f;
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (*it) & 0x3f;
return UTF8_OK;
}
#undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
template <typename octet_iterator>
utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
// Save the original value of it so we can go back in case of failure
// Of course, it does not make much sense with i.e. stream iterators
octet_iterator original_it = it;
uint32_t cp = 0;
// Determine the sequence length based on the lead octet
typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
const octet_difference_type length = utf8::internal::sequence_length(it);
// Get trail octets and calculate the code point
utf_error err = UTF8_OK;
switch (length) {
case 0:
return INVALID_LEAD;
case 1:
err = utf8::internal::get_sequence_1(it, end, cp);
break;
case 2:
err = utf8::internal::get_sequence_2(it, end, cp);
break;
case 3:
err = utf8::internal::get_sequence_3(it, end, cp);
break;
case 4:
err = utf8::internal::get_sequence_4(it, end, cp);
break;
}
if (err == UTF8_OK) {
// Decoding succeeded. Now, security checks...
if (utf8::internal::is_code_point_valid(cp)) {
if (!utf8::internal::is_overlong_sequence(cp, length)){
// Passed! Return here.
code_point = cp;
++it;
return UTF8_OK;
}
else
err = OVERLONG_SEQUENCE;
}
else
err = INVALID_CODE_POINT;
}
// Failure branch - restore the original value of the iterator
it = original_it;
return err;
}
template <typename octet_iterator>
inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
uint32_t ignored;
return utf8::internal::validate_next(it, end, ignored);
}
} // namespace internal
/// The library API - functions intended to be called by the users
// Byte order mark
constexpr uint8_t bom[] = {0xef, 0xbb, 0xbf};
template <typename octet_iterator>
octet_iterator find_invalid(octet_iterator start, octet_iterator end)
{
octet_iterator result = start;
while (result != end) {
utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
if (err_code != internal::UTF8_OK)
return result;
}
return result;
}
template <typename octet_iterator>
inline bool is_valid(octet_iterator start, octet_iterator end)
{
return (utf8::find_invalid(start, end) == end);
}
template <typename octet_iterator>
inline bool starts_with_bom (octet_iterator it, octet_iterator end)
{
return (
((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
((it != end) && (utf8::internal::mask8(*it)) == bom[2])
);
}
} // namespace utf8
#endif // header guard

View File

@ -0,0 +1,103 @@
// Copyright 2018 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_a184c22c_d012_11e8_a8d5_f2801f1b9fd1
#define UTF8_FOR_CPP_a184c22c_d012_11e8_a8d5_f2801f1b9fd1
#include "checked.h"
#include <string>
namespace utf8
{
inline void append(char32_t cp, std::string& s)
{
append(uint32_t(cp), std::back_inserter(s));
}
inline std::string utf16to8(const std::u16string& s)
{
std::string result;
utf16to8(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::u16string utf8to16(const std::string& s)
{
std::u16string result;
utf8to16(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::string utf32to8(const std::u32string& s)
{
std::string result;
utf32to8(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::u32string utf8to32(const std::string& s)
{
std::u32string result;
utf8to32(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::size_t find_invalid(const std::string& s)
{
std::string::const_iterator invalid = find_invalid(s.begin(), s.end());
return (invalid == s.end()) ? std::string::npos : (invalid - s.begin());
}
inline bool is_valid(const std::string& s)
{
return is_valid(s.begin(), s.end());
}
inline std::string replace_invalid(const std::string& s, char32_t replacement)
{
std::string result;
replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement);
return result;
}
inline std::string replace_invalid(const std::string& s)
{
std::string result;
replace_invalid(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline bool starts_with_bom(const std::string& s)
{
return starts_with_bom(s.begin(), s.end());
}
} // namespace utf8
#endif // header guard

View File

@ -0,0 +1,103 @@
// Copyright 2018 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_7e906c01_03a3_4daf_b420_ea7ea952b3c9
#define UTF8_FOR_CPP_7e906c01_03a3_4daf_b420_ea7ea952b3c9
#include "checked.h"
#include <string>
namespace utf8
{
inline void append(char32_t cp, std::string& s)
{
append(uint32_t(cp), std::back_inserter(s));
}
inline std::string utf16to8(std::u16string_view s)
{
std::string result;
utf16to8(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::u16string utf8to16(std::string_view s)
{
std::u16string result;
utf8to16(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::string utf32to8(std::u32string_view s)
{
std::string result;
utf32to8(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::u32string utf8to32(std::string_view s)
{
std::u32string result;
utf8to32(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::size_t find_invalid(std::string_view s)
{
std::string_view::const_iterator invalid = find_invalid(s.begin(), s.end());
return (invalid == s.end()) ? std::string_view::npos : (invalid - s.begin());
}
inline bool is_valid(std::string_view s)
{
return is_valid(s.begin(), s.end());
}
inline std::string replace_invalid(std::string_view s, char32_t replacement)
{
std::string result;
replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement);
return result;
}
inline std::string replace_invalid(std::string_view s)
{
std::string result;
replace_invalid(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline bool starts_with_bom(std::string_view s)
{
return starts_with_bom(s.begin(), s.end());
}
} // namespace utf8
#endif // header guard

View File

@ -0,0 +1,274 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include "core.h"
namespace utf8
{
namespace unchecked
{
template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result)
{
if (cp < 0x80) // one octet
*(result++) = static_cast<uint8_t>(cp);
else if (cp < 0x800) { // two octets
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else if (cp < 0x10000) { // three octets
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else { // four octets
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
return result;
}
template <typename octet_iterator, typename output_iterator>
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
{
while (start != end) {
octet_iterator sequence_start = start;
internal::utf_error err_code = utf8::internal::validate_next(start, end);
switch (err_code) {
case internal::UTF8_OK :
for (octet_iterator it = sequence_start; it != start; ++it)
*out++ = *it;
break;
case internal::NOT_ENOUGH_ROOM:
out = utf8::unchecked::append (replacement, out);
start = end;
break;
case internal::INVALID_LEAD:
out = utf8::unchecked::append (replacement, out);
++start;
break;
case internal::INCOMPLETE_SEQUENCE:
case internal::OVERLONG_SEQUENCE:
case internal::INVALID_CODE_POINT:
out = utf8::unchecked::append (replacement, out);
++start;
// just one replacement mark for the sequence
while (start != end && utf8::internal::is_trail(*start))
++start;
break;
}
}
return out;
}
template <typename octet_iterator, typename output_iterator>
inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
{
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
return utf8::unchecked::replace_invalid(start, end, out, replacement_marker);
}
template <typename octet_iterator>
uint32_t next(octet_iterator& it)
{
uint32_t cp = utf8::internal::mask8(*it);
typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it);
switch (length) {
case 1:
break;
case 2:
it++;
cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
break;
case 3:
++it;
cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
++it;
cp += (*it) & 0x3f;
break;
case 4:
++it;
cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
++it;
cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
++it;
cp += (*it) & 0x3f;
break;
}
++it;
return cp;
}
template <typename octet_iterator>
uint32_t peek_next(octet_iterator it)
{
return utf8::unchecked::next(it);
}
template <typename octet_iterator>
uint32_t prior(octet_iterator& it)
{
while (utf8::internal::is_trail(*(--it))) ;
octet_iterator temp = it;
return utf8::unchecked::next(temp);
}
template <typename octet_iterator, typename distance_type>
void advance (octet_iterator& it, distance_type n)
{
const distance_type zero(0);
if (n < zero) {
// backward
for (distance_type i = n; i < zero; ++i)
utf8::unchecked::prior(it);
} else {
// forward
for (distance_type i = zero; i < n; ++i)
utf8::unchecked::next(it);
}
}
template <typename octet_iterator>
typename std::iterator_traits<octet_iterator>::difference_type
distance (octet_iterator first, octet_iterator last)
{
typename std::iterator_traits<octet_iterator>::difference_type dist;
for (dist = 0; first < last; ++dist)
utf8::unchecked::next(first);
return dist;
}
template <typename u16bit_iterator, typename octet_iterator>
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
{
while (start != end) {
uint32_t cp = utf8::internal::mask16(*start++);
// Take care of surrogate pairs first
if (utf8::internal::is_lead_surrogate(cp)) {
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
}
result = utf8::unchecked::append(cp, result);
}
return result;
}
template <typename u16bit_iterator, typename octet_iterator>
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
{
while (start < end) {
uint32_t cp = utf8::unchecked::next(start);
if (cp > 0xffff) { //make a surrogate pair
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
}
else
*result++ = static_cast<uint16_t>(cp);
}
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
{
while (start != end)
result = utf8::unchecked::append(*(start++), result);
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
{
while (start < end)
(*result++) = utf8::unchecked::next(start);
return result;
}
// The iterator class
template <typename octet_iterator>
class iterator {
octet_iterator it;
public:
typedef uint32_t value_type;
typedef uint32_t* pointer;
typedef uint32_t& reference;
typedef std::ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
iterator () {}
explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
// the default "big three" are OK
octet_iterator base () const { return it; }
uint32_t operator * () const
{
octet_iterator temp = it;
return utf8::unchecked::next(temp);
}
bool operator == (const iterator& rhs) const
{
return (it == rhs.it);
}
bool operator != (const iterator& rhs) const
{
return !(operator == (rhs));
}
iterator& operator ++ ()
{
::std::advance(it, utf8::internal::sequence_length(it));
return *this;
}
iterator operator ++ (int)
{
iterator temp = *this;
::std::advance(it, utf8::internal::sequence_length(it));
return temp;
}
iterator& operator -- ()
{
utf8::unchecked::prior(it);
return *this;
}
iterator operator -- (int)
{
iterator temp = *this;
utf8::unchecked::prior(it);
return temp;
}
}; // class iterator
} // namespace utf8::unchecked
} // namespace utf8
#endif // header guard

25603
overlay_experimental/glad/gl.h Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <set>
#include "Base_Hook.h"
#include "Renderer_Hook.h"
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64)
#include <windows.h>
#ifdef GetModuleHandle
#undef GetModuleHandle
#endif
#endif
#ifdef USE_SPDLOG
#define SPDLOG_ACTIVE_LEVEL 0
#include <spdlog/spdlog.h>
#endif
#ifndef SPDLOG_TRACE
#define SPDLOG_TRACE(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
#endif
#ifndef SPDLOG_DEBUG
#define SPDLOG_DEBUG(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
#endif
#ifndef SPDLOG_INFO
#define SPDLOG_INFO(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
#endif
#ifndef SPDLOG_WARN
#define SPDLOG_WARN(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
#endif
#ifndef SPDLOG_ERROR
#define SPDLOG_ERROR(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
#endif

View File

@ -1,151 +1,164 @@
/*
* Copyright (C) 2019-2020 Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include <glad/gl.h>
#include "OpenGLX_Hook.h" #include "OpenGLX_Hook.h"
#include "X11_Hook.h" #include "X11_Hook.h"
#include "../Renderer_Detector.h"
#include "../dll/dll.h"
#ifdef __LINUX__
#ifdef EMU_OVERLAY
#include <imgui.h> #include <imgui.h>
#include <impls/imgui_impl_opengl3.h> #include <backends/imgui_impl_opengl3.h>
#include "../steam_overlay.h"
OpenGLX_Hook* OpenGLX_Hook::_inst = nullptr; OpenGLX_Hook* OpenGLX_Hook::_inst = nullptr;
bool OpenGLX_Hook::start_hook() constexpr decltype(OpenGLX_Hook::DLL_NAME) OpenGLX_Hook::DLL_NAME;
bool OpenGLX_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
{ {
bool res = true; if (!_Hooked)
if (!hooked)
{ {
if (!X11_Hook::Inst()->start_hook()) if (glXSwapBuffers == nullptr)
{
SPDLOG_WARN("Failed to hook OpenGLX: Rendering functions missing.");
return false;
}
if (!X11_Hook::Inst()->StartHook(key_combination_callback))
return false; return false;
GLenum err = glewInit(); _X11Hooked = true;
if (err == GLEW_OK) SPDLOG_INFO("Hooked OpenGLX");
{
PRINT_DEBUG("Hooked OpenGLX\n");
hooked = true; _Hooked = true;
Renderer_Detector::Inst().renderer_found(this);
/* UnhookAll();
UnhookAll(); BeginHook();
BeginHook(); HookFuncs(
HookFuncs( std::make_pair<void**, void*>((void**)&glXSwapBuffers, (void*)&OpenGLX_Hook::MyglXSwapBuffers)
std::make_pair<void**, void*>(&(void*&)_glXSwapBuffers, (void*)&OpenGLX_Hook::MyglXSwapBuffers) );
); EndHook();
EndHook();
*/
get_steam_client()->steam_overlay->HookReady();
}
else
{
PRINT_DEBUG("Failed to hook OpenGLX\n");
/* Problem: glewInit failed, something is seriously wrong. */
PRINT_DEBUG("Error: %s\n", glewGetErrorString(err));
res = false;
}
} }
return true; return true;
} }
void OpenGLX_Hook::resetRenderState() bool OpenGLX_Hook::IsStarted()
{ {
if (initialized) return _Hooked;
}
void OpenGLX_Hook::_ResetRenderState()
{
if (_Initialized)
{ {
OverlayHookReady(false);
ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplOpenGL3_Shutdown();
X11_Hook::Inst()->resetRenderState(); X11_Hook::Inst()->ResetRenderState();
ImGui::DestroyContext(); ImGui::DestroyContext();
glXDestroyContext(display, context); glXDestroyContext(_Display, _Context);
display = nullptr; _Display = nullptr;
initialized = false; _Initialized = false;
} }
} }
// Try to make this function and overlay's proc as short as possible or it might affect game's fps. // Try to make this function and overlay's proc as short as possible or it might affect game's fps.
void OpenGLX_Hook::prepareForOverlay(Display* display, GLXDrawable drawable) void OpenGLX_Hook::_PrepareForOverlay(Display* display, GLXDrawable drawable)
{ {
PRINT_DEBUG("Called SwapBuffer hook"); if( !_Initialized )
if( (Window)drawable != X11_Hook::Inst()->get_game_wnd() )
X11_Hook::Inst()->resetRenderState();
if( ! initialized )
{ {
ImGui::CreateContext(); ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.IniFilename = NULL;
ImGui_ImplOpenGL3_Init(); ImGui_ImplOpenGL3_Init();
int attributes[] = { //can't be const b/c X11 doesn't like it. Not sure if that's intentional or just stupid. //int attributes[] = { //can't be const b/c X11 doesn't like it. Not sure if that's intentional or just stupid.
GLX_RGBA, //apparently nothing comes after this? // GLX_RGBA, //apparently nothing comes after this?
GLX_RED_SIZE, 8, // GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8, // GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8, // GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8, // GLX_ALPHA_SIZE, 8,
//Ideally, the size would be 32 (or at least 24), but I have actually seen // //Ideally, the size would be 32 (or at least 24), but I have actually seen
// this size (on a modern OS even). // // this size (on a modern OS even).
GLX_DEPTH_SIZE, 16, // GLX_DEPTH_SIZE, 16,
GLX_DOUBLEBUFFER, True, // GLX_DOUBLEBUFFER, True,
None // None
}; //};
//
//XVisualInfo* visual_info = glXChooseVisual(_Display, DefaultScreen(_Display), attributes);
//if (visual_info == nullptr)
// return;
//
//_Context = glXCreateContext(_Display, visual_info, nullptr, True);
//if (_Context == nullptr)
// return;
XVisualInfo* visual_info = glXChooseVisual(display, DefaultScreen(display), attributes); _Display = display;
context = glXCreateContext(display, visual_info, nullptr, True); _Initialized = true;
this->display = display; OverlayHookReady(true);
get_steam_client()->steam_overlay->CreateFonts();
initialized = true;
} }
auto oldContext = glXGetCurrentContext(); //auto oldContext = glXGetCurrentContext();
glXMakeCurrent(display, drawable, context); //glXMakeCurrent(_Display, drawable, _Context);
ImGui_ImplOpenGL3_NewFrame(); if (ImGui_ImplOpenGL3_NewFrame() && X11_Hook::Inst()->PrepareForOverlay(_Display, (Window)drawable))
X11_Hook::Inst()->prepareForOverlay(display, (Window)drawable); {
ImGui::NewFrame();
ImGui::NewFrame(); OverlayProc();
get_steam_client()->steam_overlay->OverlayProc(); ImGui::Render();
ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); //glXMakeCurrent(_Display, drawable, oldContext);
glXMakeCurrent(display, drawable, oldContext);
} }
void OpenGLX_Hook::MyglXSwapBuffers(Display* display, GLXDrawable drawable) void OpenGLX_Hook::MyglXSwapBuffers(Display* display, GLXDrawable drawable)
{ {
OpenGLX_Hook::Inst()->prepareForOverlay(display, drawable); OpenGLX_Hook::Inst()->_PrepareForOverlay(display, drawable);
OpenGLX_Hook::Inst()->_glXSwapBuffers(display, drawable); OpenGLX_Hook::Inst()->glXSwapBuffers(display, drawable);
} }
OpenGLX_Hook::OpenGLX_Hook(): OpenGLX_Hook::OpenGLX_Hook():
initialized(false), _Initialized(false),
hooked(false), _Hooked(false),
_glXSwapBuffers(nullptr) _X11Hooked(false),
glXSwapBuffers(nullptr)
{ {
//_library = dlopen(DLL_NAME); //_library = dlopen(DLL_NAME);
} }
OpenGLX_Hook::~OpenGLX_Hook() OpenGLX_Hook::~OpenGLX_Hook()
{ {
PRINT_DEBUG("OpenGLX Hook removed\n"); SPDLOG_INFO("OpenGLX Hook removed");
if (initialized) if (_X11Hooked)
delete X11_Hook::Inst();
if (_Initialized)
{ {
ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplOpenGL3_Shutdown();
ImGui::DestroyContext(); ImGui::DestroyContext();
glXDestroyContext(display, context); glXDestroyContext(_Display, _Context);
} }
//dlclose(_library); //dlclose(_library);
@ -161,15 +174,62 @@ OpenGLX_Hook* OpenGLX_Hook::Inst()
return _inst; return _inst;
} }
const char* OpenGLX_Hook::get_lib_name() const std::string OpenGLX_Hook::GetLibraryName() const
{ {
return DLL_NAME; return LibraryName;
} }
void OpenGLX_Hook::loadFunctions(decltype(glXSwapBuffers)* pfnglXSwapBuffers) void OpenGLX_Hook::LoadFunctions(decltype(::glXSwapBuffers)* pfnglXSwapBuffers)
{ {
_glXSwapBuffers = pfnglXSwapBuffers; glXSwapBuffers = pfnglXSwapBuffers;
} }
#endif//EMU_OVERLAY std::weak_ptr<uint64_t> OpenGLX_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
#endif//__LINUX__ {
GLuint* texture = new GLuint(0);
glGenTextures(1, texture);
if (glGetError() != GL_NO_ERROR)
{
delete texture;
return std::shared_ptr<uint64_t>(nullptr);
}
// Save old texture id
GLint oldTex;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex);
glBindTexture(GL_TEXTURE_2D, *texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Upload pixels into texture
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
glBindTexture(GL_TEXTURE_2D, oldTex);
auto ptr = std::shared_ptr<uint64_t>((uint64_t*)texture, [](uint64_t* handle)
{
if (handle != nullptr)
{
GLuint* texture = (GLuint*)handle;
glDeleteTextures(1, texture);
delete texture;
}
});
_ImageResources.emplace(ptr);
return ptr;
}
void OpenGLX_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
{
auto ptr = resource.lock();
if (ptr)
{
auto it = _ImageResources.find(ptr);
if (it != _ImageResources.end())
_ImageResources.erase(it);
}
}

View File

@ -1,14 +1,33 @@
#ifndef __INCLUDED_OPENGLX_HOOK_H__ /*
#define __INCLUDED_OPENGLX_HOOK_H__ * Copyright (C) 2019-2020 Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "../Base_Hook.h" #pragma once
#include <ingame_overlay/Renderer_Hook.h>
#include "../internal_includes.h"
#ifdef __LINUX__
#ifdef EMU_OVERLAY
#include <GL/glew.h>
#include <GL/glx.h> #include <GL/glx.h>
class OpenGLX_Hook : public Base_Hook class OpenGLX_Hook :
public Renderer_Hook,
public Base_Hook
{ {
public: public:
static constexpr const char *DLL_NAME = "libGLX.so"; static constexpr const char *DLL_NAME = "libGLX.so";
@ -17,33 +36,35 @@ private:
static OpenGLX_Hook* _inst; static OpenGLX_Hook* _inst;
// Variables // Variables
bool hooked; bool _Hooked;
bool initialized; bool _X11Hooked;
Display *display; bool _Initialized;
GLXContext context; Display *_Display;
GLXContext _Context;
std::set<std::shared_ptr<uint64_t>> _ImageResources;
// Functions // Functions
OpenGLX_Hook(); OpenGLX_Hook();
void resetRenderState(); void _ResetRenderState();
void prepareForOverlay(Display* display, GLXDrawable drawable); void _PrepareForOverlay(Display* display, GLXDrawable drawable);
// Hook to render functions // Hook to render functions
decltype(::glXSwapBuffers)* glXSwapBuffers;
decltype(glXSwapBuffers)* _glXSwapBuffers;
public: public:
std::string LibraryName;
static void MyglXSwapBuffers(Display* display, GLXDrawable drawable); static void MyglXSwapBuffers(Display* display, GLXDrawable drawable);
virtual ~OpenGLX_Hook(); virtual ~OpenGLX_Hook();
bool start_hook(); virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
virtual bool IsStarted();
static OpenGLX_Hook* Inst(); static OpenGLX_Hook* Inst();
virtual const char* get_lib_name() const; virtual std::string GetLibraryName() const;
void loadFunctions(decltype(glXSwapBuffers)* pfnglXSwapBuffers); void LoadFunctions(decltype(::glXSwapBuffers)* pfnglXSwapBuffers);
};
#endif//EMU_OVERLAY virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
#endif//__LINUX__ virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
#endif//__INCLUDED_OPENGLX_HOOK_H__ };

View File

@ -1,54 +1,107 @@
#include "X11_Hook.h" /*
#include "../Renderer_Detector.h" * Copyright (C) 2019-2020 Nemirtingas
#include "../dll/dll.h" * This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#ifdef __LINUX__ #include "X11_Hook.h"
#ifdef EMU_OVERLAY
#include <imgui.h> #include <imgui.h>
#include <impls/linux/imgui_impl_x11.h> #include <backends/imgui_impl_x11.h>
#include <System/Library.h>
#include <dlfcn.h>
#include <unistd.h>
#include <fstream>
extern int ImGui_ImplX11_EventHandler(XEvent &event); extern int ImGui_ImplX11_EventHandler(XEvent &event);
constexpr decltype(X11_Hook::DLL_NAME) X11_Hook::DLL_NAME;
X11_Hook* X11_Hook::_inst = nullptr; X11_Hook* X11_Hook::_inst = nullptr;
bool X11_Hook::start_hook() bool X11_Hook::StartHook(std::function<bool(bool)>& _key_combination_callback)
{ {
bool res = true; if (!_Hooked)
if (!hooked)
{ {
PRINT_DEBUG("Hooked X11\n"); void* hX11 = System::Library::GetLibraryHandle(DLL_NAME);
hooked = true; if (hX11 == nullptr)
{
SPDLOG_WARN("Failed to hook X11: Cannot find {}", DLL_NAME);
return false;
}
System::Library::Library libX11;
LibraryName = System::Library::GetLibraryPath(hX11);
if (!libX11.OpenLibrary(LibraryName, false))
{
SPDLOG_WARN("Failed to hook X11: Cannot load {}", LibraryName);
return false;
}
XEventsQueued = libX11.GetSymbol<decltype(::XEventsQueued)>("XEventsQueued");
XPending = libX11.GetSymbol<decltype(::XPending)>("XPending");
if (XPending == nullptr || XEventsQueued == nullptr)
{
SPDLOG_WARN("Failed to hook X11: Cannot load functions.({}, {})", DLL_NAME, (void*)XEventsQueued, (void*)XPending);
return false;
}
SPDLOG_INFO("Hooked X11");
_KeyCombinationCallback = std::move(_key_combination_callback);
_Hooked = true;
UnhookAll();
BeginHook();
HookFuncs(
std::make_pair<void**, void*>(&(void*&)XEventsQueued, (void*)&X11_Hook::MyXEventsQueued),
std::make_pair<void**, void*>(&(void*&)XPending, (void*)&X11_Hook::MyXPending)
);
EndHook();
} }
return res; return true;
} }
void X11_Hook::resetRenderState() void X11_Hook::ResetRenderState()
{ {
if (initialized) if (_Initialized)
{ {
game_wnd = 0; _GameWnd = 0;
initialized = false; _Initialized = false;
ImGui_ImplX11_Shutdown(); ImGui_ImplX11_Shutdown();
} }
} }
void X11_Hook::prepareForOverlay(Display *display, Window wnd) bool X11_Hook::PrepareForOverlay(Display *display, Window wnd)
{ {
if (!initialized) if(!_Hooked)
return false;
if (_GameWnd != wnd)
ResetRenderState();
if (!_Initialized)
{ {
ImGui_ImplX11_Init(display, (void*)wnd); ImGui_ImplX11_Init(display, (void*)wnd);
_GameWnd = wnd;
game_wnd = wnd; _Initialized = true;
initialized = true;
} }
ImGui_ImplX11_NewFrame(); ImGui_ImplX11_NewFrame();
return true;
} }
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
@ -63,65 +116,56 @@ bool IgnoreEvent(XEvent &event)
case ButtonPress: case ButtonRelease: case ButtonPress: case ButtonRelease:
// Mouse move // Mouse move
case MotionNotify: case MotionNotify:
// Copy to clipboard request
case SelectionRequest:
return true; return true;
} }
return false; return false;
} }
int X11_Hook::check_for_overlay(Display *d, int num_events) int X11_Hook::_CheckForOverlay(Display *d, int num_events)
{ {
static Time prev_time = {}; static Time prev_time = {};
X11_Hook* inst = Inst(); X11_Hook* inst = Inst();
if( inst->initialized ) if( inst->_Initialized )
{ {
XEvent event; XEvent event;
while(num_events) while(num_events)
{ {
//inst->_XPeekEvent(d, &event); bool skip_input = inst->_KeyCombinationCallback(false);
XPeekEvent(d, &event);
XPeekEvent(d, &event);
ImGui_ImplX11_EventHandler(event);
Steam_Overlay* overlay = get_steam_client()->steam_overlay;
bool show = overlay->ShowOverlay();
// Is the event is a key press // Is the event is a key press
if (event.type == KeyPress) if (event.type == KeyPress)
{ {
// Tab is pressed and was not pressed before // Tab is pressed and was not pressed before
//if (event.xkey.keycode == inst->_XKeysymToKeycode(d, XK_Tab) && event.xkey.state & ShiftMask)
if (event.xkey.keycode == XKeysymToKeycode(d, XK_Tab) && event.xkey.state & ShiftMask) if (event.xkey.keycode == XKeysymToKeycode(d, XK_Tab) && event.xkey.state & ShiftMask)
{ {
// if key TAB is held, don't make the overlay flicker :p // if key TAB is held, don't make the overlay flicker :p
if( event.xkey.time != prev_time) if (event.xkey.time != prev_time)
{ {
overlay->ShowOverlay(!overlay->ShowOverlay()); skip_input = true;
inst->_KeyCombinationCallback(true);
if (overlay->ShowOverlay())
show = true;
} }
} }
} }
//else if(event.type == KeyRelease && event.xkey.keycode == inst->_XKeysymToKeycode(d, XK_Tab))
else if(event.type == KeyRelease && event.xkey.keycode == XKeysymToKeycode(d, XK_Tab)) else if(event.type == KeyRelease && event.xkey.keycode == XKeysymToKeycode(d, XK_Tab))
{ {
prev_time = event.xkey.time; prev_time = event.xkey.time;
} }
if (show) if (!skip_input || !IgnoreEvent(event))
{ {
ImGui_ImplX11_EventHandler(event); if(num_events)
num_events = 1;
if (IgnoreEvent(event))
{
//inst->_XNextEvent(d, &event);
XNextEvent(d, &event);
--num_events;
}
else
break;
}
else
break; break;
}
XNextEvent(d, &event);
--num_events;
} }
} }
return num_events; return num_events;
@ -131,33 +175,23 @@ int X11_Hook::MyXEventsQueued(Display *display, int mode)
{ {
X11_Hook* inst = X11_Hook::Inst(); X11_Hook* inst = X11_Hook::Inst();
int res = inst->_XEventsQueued(display, mode); int res = inst->XEventsQueued(display, mode);
if( res ) if( res )
{ {
res = inst->check_for_overlay(display, res); res = inst->_CheckForOverlay(display, res);
} }
return res; return res;
} }
int X11_Hook::MyXNextEvent(Display* display, XEvent *event)
{
return Inst()->_XNextEvent(display, event);
}
int X11_Hook::MyXPeekEvent(Display* display, XEvent *event)
{
return Inst()->_XPeekEvent(display, event);
}
int X11_Hook::MyXPending(Display* display) int X11_Hook::MyXPending(Display* display)
{ {
int res = Inst()->_XPending(display); int res = Inst()->XPending(display);
if( res ) if( res )
{ {
res = Inst()->check_for_overlay(display, res); res = Inst()->_CheckForOverlay(display, res);
} }
return res; return res;
@ -166,24 +200,19 @@ int X11_Hook::MyXPending(Display* display)
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
X11_Hook::X11_Hook() : X11_Hook::X11_Hook() :
initialized(false), _Initialized(false),
hooked(false), _Hooked(false),
game_wnd(0), _GameWnd(0),
_XEventsQueued(nullptr), XEventsQueued(nullptr),
_XPeekEvent(nullptr), XPending(nullptr)
_XNextEvent(nullptr),
_XPending(nullptr)
{ {
//_library = dlopen(DLL_NAME, RTLD_NOW);
} }
X11_Hook::~X11_Hook() X11_Hook::~X11_Hook()
{ {
PRINT_DEBUG("X11 Hook removed\n"); SPDLOG_INFO("X11 Hook removed");
resetRenderState(); ResetRenderState();
//dlclose(_library);
_inst = nullptr; _inst = nullptr;
} }
@ -196,10 +225,7 @@ X11_Hook* X11_Hook::Inst()
return _inst; return _inst;
} }
const char* X11_Hook::get_lib_name() const std::string X11_Hook::GetLibraryName() const
{ {
return DLL_NAME; return LibraryName;
} }
#endif//EMU_OVERLAY
#endif//#__LINUX__

View File

@ -1,63 +1,70 @@
#ifndef __INCLUDED_X11_HOOK_H__ /*
#define __INCLUDED_X11_HOOK_H__ * Copyright (C) 2019-2020 Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "../Base_Hook.h" #pragma once
#ifdef __LINUX__ #include <ingame_overlay/Renderer_Hook.h>
#ifdef EMU_OVERLAY
#include "../internal_includes.h"
#include <X11/X.h> // XEvent types #include <X11/X.h> // XEvent types
#include <X11/Xlib.h> // XEvent structure #include <X11/Xlib.h> // XEvent structure
#include <X11/Xutil.h> // XEvent keysym
extern "C" int XEventsQueued(Display *display, int mode); class X11_Hook :
extern "C" int XPending(Display *display); public Base_Hook
class X11_Hook : public Base_Hook
{ {
public: public:
friend int XEventsQueued(Display *display, int mode);
friend int XPending(Display *display);
static constexpr const char* DLL_NAME = "libX11.so"; static constexpr const char* DLL_NAME = "libX11.so";
private: private:
static X11_Hook* _inst; static X11_Hook* _inst;
// Variables // Variables
bool hooked; bool _Hooked;
bool initialized; bool _Initialized;
Window game_wnd; Window _GameWnd;
// Functions // Functions
X11_Hook(); X11_Hook();
int check_for_overlay(Display *d, int num_events); int _CheckForOverlay(Display *d, int num_events);
// Hook to X11 window messages // Hook to X11 window messages
decltype(XEventsQueued)* _XEventsQueued; decltype(::XEventsQueued)* XEventsQueued;
decltype(XPeekEvent)* _XPeekEvent; decltype(::XPending)* XPending;
decltype(XNextEvent)* _XNextEvent;
decltype(XPending)* _XPending;
//decltype(XKeysymToKeycode)* _XKeysymToKeycode;
//decltype(XLookupKeysym)* _XLookupKeysym;
//decltype(XGetGeometry)* _XGetGeometry;
static int MyXEventsQueued(Display * display, int mode); static int MyXEventsQueued(Display * display, int mode);
static int MyXNextEvent(Display* display, XEvent *event);
static int MyXPeekEvent(Display* display, XEvent *event);
static int MyXPending(Display* display); static int MyXPending(Display* display);
std::function<bool(bool)> _KeyCombinationCallback;
public: public:
std::string LibraryName;
virtual ~X11_Hook(); virtual ~X11_Hook();
void resetRenderState(); void ResetRenderState();
void prepareForOverlay(Display *display, Window wnd); bool PrepareForOverlay(Display *display, Window wnd);
Window get_game_wnd() const{ return game_wnd; } Window GetGameWnd() const{ return _GameWnd; }
bool start_hook(); bool StartHook(std::function<bool(bool)>& key_combination_callback);
static X11_Hook* Inst(); static X11_Hook* Inst();
virtual const char* get_lib_name() const; virtual std::string GetLibraryName() const;
}; };
#endif//EMU_OVERLAY
#endif//__LINUX__
#endif//__INCLUDED_X11_HOOK_H__

View File

@ -0,0 +1,236 @@
//
// File: vk_icd.h
//
/*
* Copyright (c) 2015-2016 The Khronos Group Inc.
* Copyright (c) 2015-2016 Valve Corporation
* Copyright (c) 2015-2016 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef VKICD_H
#define VKICD_H
#include "vulkan.h"
#include <stdbool.h>
// Loader-ICD version negotiation API. Versions add the following features:
// Version 0 - Initial. Doesn't support vk_icdGetInstanceProcAddr
// or vk_icdNegotiateLoaderICDInterfaceVersion.
// Version 1 - Add support for vk_icdGetInstanceProcAddr.
// Version 2 - Add Loader/ICD Interface version negotiation
// via vk_icdNegotiateLoaderICDInterfaceVersion.
// Version 3 - Add ICD creation/destruction of KHR_surface objects.
// Version 4 - Add unknown physical device extension qyering via
// vk_icdGetPhysicalDeviceProcAddr.
// Version 5 - Tells ICDs that the loader is now paying attention to the
// application version of Vulkan passed into the ApplicationInfo
// structure during vkCreateInstance. This will tell the ICD
// that if the loader is older, it should automatically fail a
// call for any API version > 1.0. Otherwise, the loader will
// manually determine if it can support the expected version.
// Version 6 - Add support for vk_icdEnumerateAdapterPhysicalDevices.
#define CURRENT_LOADER_ICD_INTERFACE_VERSION 6
#define MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION 0
#define MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION 4
// Old typedefs that don't follow a proper naming convention but are preserved for compatibility
typedef VkResult(VKAPI_PTR *PFN_vkNegotiateLoaderICDInterfaceVersion)(uint32_t *pVersion);
// This is defined in vk_layer.h which will be found by the loader, but if an ICD is building against this
// file directly, it won't be found.
#ifndef PFN_GetPhysicalDeviceProcAddr
typedef PFN_vkVoidFunction(VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char *pName);
#endif
// Typedefs for loader/ICD interface
typedef VkResult (VKAPI_PTR *PFN_vk_icdNegotiateLoaderICDInterfaceVersion)(uint32_t* pVersion);
typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vk_icdGetInstanceProcAddr)(VkInstance instance, const char* pName);
typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vk_icdGetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);
#if defined(VK_USE_PLATFORM_WIN32_KHR)
typedef VkResult (VKAPI_PTR *PFN_vk_icdEnumerateAdapterPhysicalDevices)(VkInstance instance, LUID adapterLUID,
uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);
#endif
// Prototypes for loader/ICD interface
#if !defined(VK_NO_PROTOTYPES)
#ifdef __cplusplus
extern "C" {
#endif
VKAPI_ATTR VkResult VKAPI_CALL vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pVersion);
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetInstanceProcAddr(VkInstance instance, const char* pName);
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetPhysicalDeviceProcAddr(VkInstance isntance, const char* pName);
#if defined(VK_USE_PLATFORM_WIN32_KHR)
VKAPI_ATTR VkResult VKAPI_CALL vk_icdEnumerateAdapterPhysicalDevices(VkInstance instance, LUID adapterLUID,
uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);
#endif
#ifdef __cplusplus
}
#endif
#endif
/*
* The ICD must reserve space for a pointer for the loader's dispatch
* table, at the start of <each object>.
* The ICD must initialize this variable using the SET_LOADER_MAGIC_VALUE macro.
*/
#define ICD_LOADER_MAGIC 0x01CDC0DE
typedef union {
uintptr_t loaderMagic;
void *loaderData;
} VK_LOADER_DATA;
static inline void set_loader_magic_value(void *pNewObject) {
VK_LOADER_DATA *loader_info = (VK_LOADER_DATA *)pNewObject;
loader_info->loaderMagic = ICD_LOADER_MAGIC;
}
static inline bool valid_loader_magic_value(void *pNewObject) {
const VK_LOADER_DATA *loader_info = (VK_LOADER_DATA *)pNewObject;
return (loader_info->loaderMagic & 0xffffffff) == ICD_LOADER_MAGIC;
}
/*
* Windows and Linux ICDs will treat VkSurfaceKHR as a pointer to a struct that
* contains the platform-specific connection and surface information.
*/
typedef enum {
VK_ICD_WSI_PLATFORM_MIR,
VK_ICD_WSI_PLATFORM_WAYLAND,
VK_ICD_WSI_PLATFORM_WIN32,
VK_ICD_WSI_PLATFORM_XCB,
VK_ICD_WSI_PLATFORM_XLIB,
VK_ICD_WSI_PLATFORM_ANDROID,
VK_ICD_WSI_PLATFORM_MACOS,
VK_ICD_WSI_PLATFORM_IOS,
VK_ICD_WSI_PLATFORM_DISPLAY,
VK_ICD_WSI_PLATFORM_HEADLESS,
VK_ICD_WSI_PLATFORM_METAL,
VK_ICD_WSI_PLATFORM_DIRECTFB,
VK_ICD_WSI_PLATFORM_VI,
VK_ICD_WSI_PLATFORM_GGP,
} VkIcdWsiPlatform;
typedef struct {
VkIcdWsiPlatform platform;
} VkIcdSurfaceBase;
#ifdef VK_USE_PLATFORM_MIR_KHR
typedef struct {
VkIcdSurfaceBase base;
MirConnection *connection;
MirSurface *mirSurface;
} VkIcdSurfaceMir;
#endif // VK_USE_PLATFORM_MIR_KHR
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
typedef struct {
VkIcdSurfaceBase base;
struct wl_display *display;
struct wl_surface *surface;
} VkIcdSurfaceWayland;
#endif // VK_USE_PLATFORM_WAYLAND_KHR
#ifdef VK_USE_PLATFORM_WIN32_KHR
typedef struct {
VkIcdSurfaceBase base;
HINSTANCE hinstance;
HWND hwnd;
} VkIcdSurfaceWin32;
#endif // VK_USE_PLATFORM_WIN32_KHR
#ifdef VK_USE_PLATFORM_XCB_KHR
typedef struct {
VkIcdSurfaceBase base;
xcb_connection_t *connection;
xcb_window_t window;
} VkIcdSurfaceXcb;
#endif // VK_USE_PLATFORM_XCB_KHR
#ifdef VK_USE_PLATFORM_XLIB_KHR
typedef struct {
VkIcdSurfaceBase base;
Display *dpy;
Window window;
} VkIcdSurfaceXlib;
#endif // VK_USE_PLATFORM_XLIB_KHR
#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
typedef struct {
VkIcdSurfaceBase base;
IDirectFB *dfb;
IDirectFBSurface *surface;
} VkIcdSurfaceDirectFB;
#endif // VK_USE_PLATFORM_DIRECTFB_EXT
#ifdef VK_USE_PLATFORM_ANDROID_KHR
typedef struct {
VkIcdSurfaceBase base;
struct ANativeWindow *window;
} VkIcdSurfaceAndroid;
#endif // VK_USE_PLATFORM_ANDROID_KHR
#ifdef VK_USE_PLATFORM_MACOS_MVK
typedef struct {
VkIcdSurfaceBase base;
const void *pView;
} VkIcdSurfaceMacOS;
#endif // VK_USE_PLATFORM_MACOS_MVK
#ifdef VK_USE_PLATFORM_IOS_MVK
typedef struct {
VkIcdSurfaceBase base;
const void *pView;
} VkIcdSurfaceIOS;
#endif // VK_USE_PLATFORM_IOS_MVK
#ifdef VK_USE_PLATFORM_GGP
typedef struct {
VkIcdSurfaceBase base;
GgpStreamDescriptor streamDescriptor;
} VkIcdSurfaceGgp;
#endif // VK_USE_PLATFORM_GGP
typedef struct {
VkIcdSurfaceBase base;
VkDisplayModeKHR displayMode;
uint32_t planeIndex;
uint32_t planeStackIndex;
VkSurfaceTransformFlagBitsKHR transform;
float globalAlpha;
VkDisplayPlaneAlphaFlagBitsKHR alphaMode;
VkExtent2D imageExtent;
} VkIcdSurfaceDisplay;
typedef struct {
VkIcdSurfaceBase base;
} VkIcdSurfaceHeadless;
#ifdef VK_USE_PLATFORM_METAL_EXT
typedef struct {
VkIcdSurfaceBase base;
const CAMetalLayer *pLayer;
} VkIcdSurfaceMetal;
#endif // VK_USE_PLATFORM_METAL_EXT
#ifdef VK_USE_PLATFORM_VI_NN
typedef struct {
VkIcdSurfaceBase base;
void *window;
} VkIcdSurfaceVi;
#endif // VK_USE_PLATFORM_VI_NN
#endif // VKICD_H

View File

@ -0,0 +1,210 @@
//
// File: vk_layer.h
//
/*
* Copyright (c) 2015-2017 The Khronos Group Inc.
* Copyright (c) 2015-2017 Valve Corporation
* Copyright (c) 2015-2017 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/* Need to define dispatch table
* Core struct can then have ptr to dispatch table at the top
* Along with object ptrs for current and next OBJ
*/
#pragma once
#include "vulkan.h"
#if defined(__GNUC__) && __GNUC__ >= 4
#define VK_LAYER_EXPORT __attribute__((visibility("default")))
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
#define VK_LAYER_EXPORT __attribute__((visibility("default")))
#else
#define VK_LAYER_EXPORT
#endif
#define MAX_NUM_UNKNOWN_EXTS 250
// Loader-Layer version negotiation API. Versions add the following features:
// Versions 0/1 - Initial. Doesn't support vk_layerGetPhysicalDeviceProcAddr
// or vk_icdNegotiateLoaderLayerInterfaceVersion.
// Version 2 - Add support for vk_layerGetPhysicalDeviceProcAddr and
// vk_icdNegotiateLoaderLayerInterfaceVersion.
#define CURRENT_LOADER_LAYER_INTERFACE_VERSION 2
#define MIN_SUPPORTED_LOADER_LAYER_INTERFACE_VERSION 1
#define VK_CURRENT_CHAIN_VERSION 1
// Typedef for use in the interfaces below
typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);
// Version negotiation values
typedef enum VkNegotiateLayerStructType {
LAYER_NEGOTIATE_UNINTIALIZED = 0,
LAYER_NEGOTIATE_INTERFACE_STRUCT = 1,
} VkNegotiateLayerStructType;
// Version negotiation structures
typedef struct VkNegotiateLayerInterface {
VkNegotiateLayerStructType sType;
void *pNext;
uint32_t loaderLayerInterfaceVersion;
PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr;
PFN_vkGetDeviceProcAddr pfnGetDeviceProcAddr;
PFN_GetPhysicalDeviceProcAddr pfnGetPhysicalDeviceProcAddr;
} VkNegotiateLayerInterface;
// Version negotiation functions
typedef VkResult (VKAPI_PTR *PFN_vkNegotiateLoaderLayerInterfaceVersion)(VkNegotiateLayerInterface *pVersionStruct);
// Function prototype for unknown physical device extension command
typedef VkResult(VKAPI_PTR *PFN_PhysDevExt)(VkPhysicalDevice phys_device);
// ------------------------------------------------------------------------------------------------
// CreateInstance and CreateDevice support structures
/* Sub type of structure for instance and device loader ext of CreateInfo.
* When sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO
* or sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO
* then VkLayerFunction indicates struct type pointed to by pNext
*/
typedef enum VkLayerFunction_ {
VK_LAYER_LINK_INFO = 0,
VK_LOADER_DATA_CALLBACK = 1,
VK_LOADER_LAYER_CREATE_DEVICE_CALLBACK = 2,
VK_LOADER_FEATURES = 3,
} VkLayerFunction;
typedef struct VkLayerInstanceLink_ {
struct VkLayerInstanceLink_ *pNext;
PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
PFN_GetPhysicalDeviceProcAddr pfnNextGetPhysicalDeviceProcAddr;
} VkLayerInstanceLink;
/*
* When creating the device chain the loader needs to pass
* down information about it's device structure needed at
* the end of the chain. Passing the data via the
* VkLayerDeviceInfo avoids issues with finding the
* exact instance being used.
*/
typedef struct VkLayerDeviceInfo_ {
void *device_info;
PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
} VkLayerDeviceInfo;
typedef VkResult (VKAPI_PTR *PFN_vkSetInstanceLoaderData)(VkInstance instance,
void *object);
typedef VkResult (VKAPI_PTR *PFN_vkSetDeviceLoaderData)(VkDevice device,
void *object);
typedef VkResult (VKAPI_PTR *PFN_vkLayerCreateDevice)(VkInstance instance, VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, PFN_vkGetInstanceProcAddr layerGIPA, PFN_vkGetDeviceProcAddr *nextGDPA);
typedef void (VKAPI_PTR *PFN_vkLayerDestroyDevice)(VkDevice physicalDevice, const VkAllocationCallbacks *pAllocator, PFN_vkDestroyDevice destroyFunction);
typedef enum VkLoaderFeastureFlagBits {
VK_LOADER_FEATURE_PHYSICAL_DEVICE_SORTING = 0x00000001,
} VkLoaderFlagBits;
typedef VkFlags VkLoaderFeatureFlags;
typedef struct {
VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO
const void *pNext;
VkLayerFunction function;
union {
VkLayerInstanceLink *pLayerInfo;
PFN_vkSetInstanceLoaderData pfnSetInstanceLoaderData;
struct {
PFN_vkLayerCreateDevice pfnLayerCreateDevice;
PFN_vkLayerDestroyDevice pfnLayerDestroyDevice;
} layerDevice;
VkLoaderFeatureFlags loaderFeatures;
} u;
} VkLayerInstanceCreateInfo;
typedef struct VkLayerDeviceLink_ {
struct VkLayerDeviceLink_ *pNext;
PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
PFN_vkGetDeviceProcAddr pfnNextGetDeviceProcAddr;
} VkLayerDeviceLink;
typedef struct {
VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO
const void *pNext;
VkLayerFunction function;
union {
VkLayerDeviceLink *pLayerInfo;
PFN_vkSetDeviceLoaderData pfnSetDeviceLoaderData;
} u;
} VkLayerDeviceCreateInfo;
#ifdef __cplusplus
extern "C" {
#endif
VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct);
typedef enum VkChainType {
VK_CHAIN_TYPE_UNKNOWN = 0,
VK_CHAIN_TYPE_ENUMERATE_INSTANCE_EXTENSION_PROPERTIES = 1,
VK_CHAIN_TYPE_ENUMERATE_INSTANCE_LAYER_PROPERTIES = 2,
VK_CHAIN_TYPE_ENUMERATE_INSTANCE_VERSION = 3,
} VkChainType;
typedef struct VkChainHeader {
VkChainType type;
uint32_t version;
uint32_t size;
} VkChainHeader;
typedef struct VkEnumerateInstanceExtensionPropertiesChain {
VkChainHeader header;
VkResult(VKAPI_PTR *pfnNextLayer)(const struct VkEnumerateInstanceExtensionPropertiesChain *, const char *, uint32_t *,
VkExtensionProperties *);
const struct VkEnumerateInstanceExtensionPropertiesChain *pNextLink;
#if defined(__cplusplus)
inline VkResult CallDown(const char *pLayerName, uint32_t *pPropertyCount, VkExtensionProperties *pProperties) const {
return pfnNextLayer(pNextLink, pLayerName, pPropertyCount, pProperties);
}
#endif
} VkEnumerateInstanceExtensionPropertiesChain;
typedef struct VkEnumerateInstanceLayerPropertiesChain {
VkChainHeader header;
VkResult(VKAPI_PTR *pfnNextLayer)(const struct VkEnumerateInstanceLayerPropertiesChain *, uint32_t *, VkLayerProperties *);
const struct VkEnumerateInstanceLayerPropertiesChain *pNextLink;
#if defined(__cplusplus)
inline VkResult CallDown(uint32_t *pPropertyCount, VkLayerProperties *pProperties) const {
return pfnNextLayer(pNextLink, pPropertyCount, pProperties);
}
#endif
} VkEnumerateInstanceLayerPropertiesChain;
typedef struct VkEnumerateInstanceVersionChain {
VkChainHeader header;
VkResult(VKAPI_PTR *pfnNextLayer)(const struct VkEnumerateInstanceVersionChain *, uint32_t *);
const struct VkEnumerateInstanceVersionChain *pNextLink;
#if defined(__cplusplus)
inline VkResult CallDown(uint32_t *pApiVersion) const {
return pfnNextLayer(pNextLink, pApiVersion);
}
#endif
} VkEnumerateInstanceVersionChain;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,82 @@
//
// File: vk_platform.h
//
/*
** Copyright (c) 2014-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
#ifndef VK_PLATFORM_H_
#define VK_PLATFORM_H_
#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus
/*
***************************************************************************************************
* Platform-specific directives and type declarations
***************************************************************************************************
*/
/* Platform-specific calling convention macros.
*
* Platforms should define these so that Vulkan clients call Vulkan commands
* with the same calling conventions that the Vulkan implementation expects.
*
* VKAPI_ATTR - Placed before the return type in function declarations.
* Useful for C++11 and GCC/Clang-style function attribute syntax.
* VKAPI_CALL - Placed after the return type in function declarations.
* Useful for MSVC-style calling convention syntax.
* VKAPI_PTR - Placed between the '(' and '*' in function pointer types.
*
* Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void);
* Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void);
*/
#if defined(_WIN32)
// On Windows, Vulkan commands use the stdcall convention
#define VKAPI_ATTR
#define VKAPI_CALL __stdcall
#define VKAPI_PTR VKAPI_CALL
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7
#error "Vulkan isn't supported for the 'armeabi' NDK ABI"
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE)
// On Android 32-bit ARM targets, Vulkan functions use the "hardfloat"
// calling convention, i.e. float parameters are passed in registers. This
// is true even if the rest of the application passes floats on the stack,
// as it does by default when compiling for the armeabi-v7a NDK ABI.
#define VKAPI_ATTR __attribute__((pcs("aapcs-vfp")))
#define VKAPI_CALL
#define VKAPI_PTR VKAPI_ATTR
#else
// On other platforms, use the default calling convention
#define VKAPI_ATTR
#define VKAPI_CALL
#define VKAPI_PTR
#endif
#include <stddef.h>
#if !defined(VK_NO_STDINT_H)
#if defined(_MSC_VER) && (_MSC_VER < 1600)
typedef signed __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef signed __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef signed __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
#endif // !defined(VK_NO_STDINT_H)
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif

View File

@ -0,0 +1,69 @@
//
// File: vk_sdk_platform.h
//
/*
* Copyright (c) 2015-2016 The Khronos Group Inc.
* Copyright (c) 2015-2016 Valve Corporation
* Copyright (c) 2015-2016 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef VK_SDK_PLATFORM_H
#define VK_SDK_PLATFORM_H
#if defined(_WIN32)
#define NOMINMAX
#ifndef __cplusplus
#undef inline
#define inline __inline
#endif // __cplusplus
#if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/)
// C99:
// Microsoft didn't implement C99 in Visual Studio; but started adding it with
// VS2013. However, VS2013 still didn't have snprintf(). The following is a
// work-around (Note: The _CRT_SECURE_NO_WARNINGS macro must be set in the
// "CMakeLists.txt" file).
// NOTE: This is fixed in Visual Studio 2015.
#define snprintf _snprintf
#endif
#define strdup _strdup
#endif // _WIN32
// Check for noexcept support using clang, with fallback to Windows or GCC version numbers
#ifndef NOEXCEPT
#if defined(__clang__)
#if __has_feature(cxx_noexcept)
#define HAS_NOEXCEPT
#endif
#else
#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46
#define HAS_NOEXCEPT
#else
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026 && defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS
#define HAS_NOEXCEPT
#endif
#endif
#endif
#ifdef HAS_NOEXCEPT
#define NOEXCEPT noexcept
#else
#define NOEXCEPT
#endif
#endif
#endif // VK_SDK_PLATFORM_H

View File

@ -0,0 +1,87 @@
#ifndef VULKAN_H_
#define VULKAN_H_ 1
/*
** Copyright (c) 2015-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
#include "vk_platform.h"
#include "vulkan_core.h"
#ifdef VK_USE_PLATFORM_ANDROID_KHR
#include "vulkan_android.h"
#endif
#ifdef VK_USE_PLATFORM_FUCHSIA
#include <zircon/types.h>
#include "vulkan_fuchsia.h"
#endif
#ifdef VK_USE_PLATFORM_IOS_MVK
#include "vulkan_ios.h"
#endif
#ifdef VK_USE_PLATFORM_MACOS_MVK
#include "vulkan_macos.h"
#endif
#ifdef VK_USE_PLATFORM_METAL_EXT
#include "vulkan_metal.h"
#endif
#ifdef VK_USE_PLATFORM_VI_NN
#include "vulkan_vi.h"
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
#include <wayland-client.h>
#include "vulkan_wayland.h"
#endif
#ifdef VK_USE_PLATFORM_WIN32_KHR
#include <windows.h>
#include "vulkan_win32.h"
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
#include <xcb/xcb.h>
#include "vulkan_xcb.h"
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR
#include <X11/Xlib.h>
#include "vulkan_xlib.h"
#endif
#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
#include <directfb.h>
#include "vulkan_directfb.h"
#endif
#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
#include "vulkan_xlib_xrandr.h"
#endif
#ifdef VK_USE_PLATFORM_GGP
#include <ggp_c/vulkan_types.h>
#include "vulkan_ggp.h"
#endif
#ifdef VK_ENABLE_BETA_EXTENSIONS
#include "vulkan_beta.h"
#endif
#endif // VULKAN_H_

View File

@ -0,0 +1,112 @@
#ifndef VULKAN_ANDROID_H_
#define VULKAN_ANDROID_H_ 1
/*
** Copyright (c) 2015-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/
#ifdef __cplusplus
extern "C" {
#endif
#define VK_KHR_android_surface 1
struct ANativeWindow;
#define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6
#define VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "VK_KHR_android_surface"
typedef VkFlags VkAndroidSurfaceCreateFlagsKHR;
typedef struct VkAndroidSurfaceCreateInfoKHR {
VkStructureType sType;
const void* pNext;
VkAndroidSurfaceCreateFlagsKHR flags;
struct ANativeWindow* window;
} VkAndroidSurfaceCreateInfoKHR;
typedef VkResult (VKAPI_PTR *PFN_vkCreateAndroidSurfaceKHR)(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateAndroidSurfaceKHR(
VkInstance instance,
const VkAndroidSurfaceCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface);
#endif
#define VK_ANDROID_external_memory_android_hardware_buffer 1
struct AHardwareBuffer;
#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION 3
#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME "VK_ANDROID_external_memory_android_hardware_buffer"
typedef struct VkAndroidHardwareBufferUsageANDROID {
VkStructureType sType;
void* pNext;
uint64_t androidHardwareBufferUsage;
} VkAndroidHardwareBufferUsageANDROID;
typedef struct VkAndroidHardwareBufferPropertiesANDROID {
VkStructureType sType;
void* pNext;
VkDeviceSize allocationSize;
uint32_t memoryTypeBits;
} VkAndroidHardwareBufferPropertiesANDROID;
typedef struct VkAndroidHardwareBufferFormatPropertiesANDROID {
VkStructureType sType;
void* pNext;
VkFormat format;
uint64_t externalFormat;
VkFormatFeatureFlags formatFeatures;
VkComponentMapping samplerYcbcrConversionComponents;
VkSamplerYcbcrModelConversion suggestedYcbcrModel;
VkSamplerYcbcrRange suggestedYcbcrRange;
VkChromaLocation suggestedXChromaOffset;
VkChromaLocation suggestedYChromaOffset;
} VkAndroidHardwareBufferFormatPropertiesANDROID;
typedef struct VkImportAndroidHardwareBufferInfoANDROID {
VkStructureType sType;
const void* pNext;
struct AHardwareBuffer* buffer;
} VkImportAndroidHardwareBufferInfoANDROID;
typedef struct VkMemoryGetAndroidHardwareBufferInfoANDROID {
VkStructureType sType;
const void* pNext;
VkDeviceMemory memory;
} VkMemoryGetAndroidHardwareBufferInfoANDROID;
typedef struct VkExternalFormatANDROID {
VkStructureType sType;
void* pNext;
uint64_t externalFormat;
} VkExternalFormatANDROID;
typedef VkResult (VKAPI_PTR *PFN_vkGetAndroidHardwareBufferPropertiesANDROID)(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties);
typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryAndroidHardwareBufferANDROID)(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkGetAndroidHardwareBufferPropertiesANDROID(
VkDevice device,
const struct AHardwareBuffer* buffer,
VkAndroidHardwareBufferPropertiesANDROID* pProperties);
VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryAndroidHardwareBufferANDROID(
VkDevice device,
const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo,
struct AHardwareBuffer** pBuffer);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,56 @@
#ifndef VULKAN_BETA_H_
#define VULKAN_BETA_H_ 1
/*
** Copyright (c) 2015-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/
#ifdef __cplusplus
extern "C" {
#endif
#define VK_KHR_portability_subset 1
#define VK_KHR_PORTABILITY_SUBSET_SPEC_VERSION 1
#define VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME "VK_KHR_portability_subset"
typedef struct VkPhysicalDevicePortabilitySubsetFeaturesKHR {
VkStructureType sType;
void* pNext;
VkBool32 constantAlphaColorBlendFactors;
VkBool32 events;
VkBool32 imageViewFormatReinterpretation;
VkBool32 imageViewFormatSwizzle;
VkBool32 imageView2DOn3DImage;
VkBool32 multisampleArrayImage;
VkBool32 mutableComparisonSamplers;
VkBool32 pointPolygons;
VkBool32 samplerMipLodBias;
VkBool32 separateStencilMaskRef;
VkBool32 shaderSampleRateInterpolationFunctions;
VkBool32 tessellationIsolines;
VkBool32 tessellationPointMode;
VkBool32 triangleFans;
VkBool32 vertexAttributeAccessBeyondStride;
} VkPhysicalDevicePortabilitySubsetFeaturesKHR;
typedef struct VkPhysicalDevicePortabilitySubsetPropertiesKHR {
VkStructureType sType;
void* pNext;
uint32_t minVertexInputBindingStrideAlignment;
} VkPhysicalDevicePortabilitySubsetPropertiesKHR;
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
#ifndef VULKAN_DIRECTFB_H_
#define VULKAN_DIRECTFB_H_ 1
/*
** Copyright (c) 2015-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/
#ifdef __cplusplus
extern "C" {
#endif
#define VK_EXT_directfb_surface 1
#define VK_EXT_DIRECTFB_SURFACE_SPEC_VERSION 1
#define VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME "VK_EXT_directfb_surface"
typedef VkFlags VkDirectFBSurfaceCreateFlagsEXT;
typedef struct VkDirectFBSurfaceCreateInfoEXT {
VkStructureType sType;
const void* pNext;
VkDirectFBSurfaceCreateFlagsEXT flags;
IDirectFB* dfb;
IDirectFBSurface* surface;
} VkDirectFBSurfaceCreateInfoEXT;
typedef VkResult (VKAPI_PTR *PFN_vkCreateDirectFBSurfaceEXT)(VkInstance instance, const VkDirectFBSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, IDirectFB* dfb);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateDirectFBSurfaceEXT(
VkInstance instance,
const VkDirectFBSurfaceCreateInfoEXT* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface);
VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceDirectFBPresentationSupportEXT(
VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex,
IDirectFB* dfb);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,47 @@
#ifndef VULKAN_FUCHSIA_H_
#define VULKAN_FUCHSIA_H_ 1
/*
** Copyright (c) 2015-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/
#ifdef __cplusplus
extern "C" {
#endif
#define VK_FUCHSIA_imagepipe_surface 1
#define VK_FUCHSIA_IMAGEPIPE_SURFACE_SPEC_VERSION 1
#define VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME "VK_FUCHSIA_imagepipe_surface"
typedef VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA;
typedef struct VkImagePipeSurfaceCreateInfoFUCHSIA {
VkStructureType sType;
const void* pNext;
VkImagePipeSurfaceCreateFlagsFUCHSIA flags;
zx_handle_t imagePipeHandle;
} VkImagePipeSurfaceCreateInfoFUCHSIA;
typedef VkResult (VKAPI_PTR *PFN_vkCreateImagePipeSurfaceFUCHSIA)(VkInstance instance, const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateImagePipeSurfaceFUCHSIA(
VkInstance instance,
const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,58 @@
#ifndef VULKAN_GGP_H_
#define VULKAN_GGP_H_ 1
/*
** Copyright (c) 2015-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/
#ifdef __cplusplus
extern "C" {
#endif
#define VK_GGP_stream_descriptor_surface 1
#define VK_GGP_STREAM_DESCRIPTOR_SURFACE_SPEC_VERSION 1
#define VK_GGP_STREAM_DESCRIPTOR_SURFACE_EXTENSION_NAME "VK_GGP_stream_descriptor_surface"
typedef VkFlags VkStreamDescriptorSurfaceCreateFlagsGGP;
typedef struct VkStreamDescriptorSurfaceCreateInfoGGP {
VkStructureType sType;
const void* pNext;
VkStreamDescriptorSurfaceCreateFlagsGGP flags;
GgpStreamDescriptor streamDescriptor;
} VkStreamDescriptorSurfaceCreateInfoGGP;
typedef VkResult (VKAPI_PTR *PFN_vkCreateStreamDescriptorSurfaceGGP)(VkInstance instance, const VkStreamDescriptorSurfaceCreateInfoGGP* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateStreamDescriptorSurfaceGGP(
VkInstance instance,
const VkStreamDescriptorSurfaceCreateInfoGGP* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface);
#endif
#define VK_GGP_frame_token 1
#define VK_GGP_FRAME_TOKEN_SPEC_VERSION 1
#define VK_GGP_FRAME_TOKEN_EXTENSION_NAME "VK_GGP_frame_token"
typedef struct VkPresentFrameTokenGGP {
VkStructureType sType;
const void* pNext;
GgpFrameToken frameToken;
} VkPresentFrameTokenGGP;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,47 @@
#ifndef VULKAN_IOS_H_
#define VULKAN_IOS_H_ 1
/*
** Copyright (c) 2015-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/
#ifdef __cplusplus
extern "C" {
#endif
#define VK_MVK_ios_surface 1
#define VK_MVK_IOS_SURFACE_SPEC_VERSION 3
#define VK_MVK_IOS_SURFACE_EXTENSION_NAME "VK_MVK_ios_surface"
typedef VkFlags VkIOSSurfaceCreateFlagsMVK;
typedef struct VkIOSSurfaceCreateInfoMVK {
VkStructureType sType;
const void* pNext;
VkIOSSurfaceCreateFlagsMVK flags;
const void* pView;
} VkIOSSurfaceCreateInfoMVK;
typedef VkResult (VKAPI_PTR *PFN_vkCreateIOSSurfaceMVK)(VkInstance instance, const VkIOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateIOSSurfaceMVK(
VkInstance instance,
const VkIOSSurfaceCreateInfoMVK* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,47 @@
#ifndef VULKAN_MACOS_H_
#define VULKAN_MACOS_H_ 1
/*
** Copyright (c) 2015-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/
#ifdef __cplusplus
extern "C" {
#endif
#define VK_MVK_macos_surface 1
#define VK_MVK_MACOS_SURFACE_SPEC_VERSION 3
#define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface"
typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
typedef struct VkMacOSSurfaceCreateInfoMVK {
VkStructureType sType;
const void* pNext;
VkMacOSSurfaceCreateFlagsMVK flags;
const void* pView;
} VkMacOSSurfaceCreateInfoMVK;
typedef VkResult (VKAPI_PTR *PFN_vkCreateMacOSSurfaceMVK)(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateMacOSSurfaceMVK(
VkInstance instance,
const VkMacOSSurfaceCreateInfoMVK* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,54 @@
#ifndef VULKAN_METAL_H_
#define VULKAN_METAL_H_ 1
/*
** Copyright (c) 2015-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/
#ifdef __cplusplus
extern "C" {
#endif
#define VK_EXT_metal_surface 1
#ifdef __OBJC__
@class CAMetalLayer;
#else
typedef void CAMetalLayer;
#endif
#define VK_EXT_METAL_SURFACE_SPEC_VERSION 1
#define VK_EXT_METAL_SURFACE_EXTENSION_NAME "VK_EXT_metal_surface"
typedef VkFlags VkMetalSurfaceCreateFlagsEXT;
typedef struct VkMetalSurfaceCreateInfoEXT {
VkStructureType sType;
const void* pNext;
VkMetalSurfaceCreateFlagsEXT flags;
const CAMetalLayer* pLayer;
} VkMetalSurfaceCreateInfoEXT;
typedef VkResult (VKAPI_PTR *PFN_vkCreateMetalSurfaceEXT)(VkInstance instance, const VkMetalSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateMetalSurfaceEXT(
VkInstance instance,
const VkMetalSurfaceCreateInfoEXT* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,47 @@
#ifndef VULKAN_VI_H_
#define VULKAN_VI_H_ 1
/*
** Copyright (c) 2015-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/
#ifdef __cplusplus
extern "C" {
#endif
#define VK_NN_vi_surface 1
#define VK_NN_VI_SURFACE_SPEC_VERSION 1
#define VK_NN_VI_SURFACE_EXTENSION_NAME "VK_NN_vi_surface"
typedef VkFlags VkViSurfaceCreateFlagsNN;
typedef struct VkViSurfaceCreateInfoNN {
VkStructureType sType;
const void* pNext;
VkViSurfaceCreateFlagsNN flags;
void* window;
} VkViSurfaceCreateInfoNN;
typedef VkResult (VKAPI_PTR *PFN_vkCreateViSurfaceNN)(VkInstance instance, const VkViSurfaceCreateInfoNN* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateViSurfaceNN(
VkInstance instance,
const VkViSurfaceCreateInfoNN* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,54 @@
#ifndef VULKAN_WAYLAND_H_
#define VULKAN_WAYLAND_H_ 1
/*
** Copyright (c) 2015-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/
#ifdef __cplusplus
extern "C" {
#endif
#define VK_KHR_wayland_surface 1
#define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6
#define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface"
typedef VkFlags VkWaylandSurfaceCreateFlagsKHR;
typedef struct VkWaylandSurfaceCreateInfoKHR {
VkStructureType sType;
const void* pNext;
VkWaylandSurfaceCreateFlagsKHR flags;
struct wl_display* display;
struct wl_surface* surface;
} VkWaylandSurfaceCreateInfoKHR;
typedef VkResult (VKAPI_PTR *PFN_vkCreateWaylandSurfaceKHR)(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct wl_display* display);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateWaylandSurfaceKHR(
VkInstance instance,
const VkWaylandSurfaceCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface);
VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWaylandPresentationSupportKHR(
VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex,
struct wl_display* display);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,315 @@
#ifndef VULKAN_WIN32_H_
#define VULKAN_WIN32_H_ 1
/*
** Copyright (c) 2015-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/
#ifdef __cplusplus
extern "C" {
#endif
#define VK_KHR_win32_surface 1
#define VK_KHR_WIN32_SURFACE_SPEC_VERSION 6
#define VK_KHR_WIN32_SURFACE_EXTENSION_NAME "VK_KHR_win32_surface"
typedef VkFlags VkWin32SurfaceCreateFlagsKHR;
typedef struct VkWin32SurfaceCreateInfoKHR {
VkStructureType sType;
const void* pNext;
VkWin32SurfaceCreateFlagsKHR flags;
HINSTANCE hinstance;
HWND hwnd;
} VkWin32SurfaceCreateInfoKHR;
typedef VkResult (VKAPI_PTR *PFN_vkCreateWin32SurfaceKHR)(VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateWin32SurfaceKHR(
VkInstance instance,
const VkWin32SurfaceCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface);
VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWin32PresentationSupportKHR(
VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex);
#endif
#define VK_KHR_external_memory_win32 1
#define VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
#define VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHR_external_memory_win32"
typedef struct VkImportMemoryWin32HandleInfoKHR {
VkStructureType sType;
const void* pNext;
VkExternalMemoryHandleTypeFlagBits handleType;
HANDLE handle;
LPCWSTR name;
} VkImportMemoryWin32HandleInfoKHR;
typedef struct VkExportMemoryWin32HandleInfoKHR {
VkStructureType sType;
const void* pNext;
const SECURITY_ATTRIBUTES* pAttributes;
DWORD dwAccess;
LPCWSTR name;
} VkExportMemoryWin32HandleInfoKHR;
typedef struct VkMemoryWin32HandlePropertiesKHR {
VkStructureType sType;
void* pNext;
uint32_t memoryTypeBits;
} VkMemoryWin32HandlePropertiesKHR;
typedef struct VkMemoryGetWin32HandleInfoKHR {
VkStructureType sType;
const void* pNext;
VkDeviceMemory memory;
VkExternalMemoryHandleTypeFlagBits handleType;
} VkMemoryGetWin32HandleInfoKHR;
typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleKHR)(VkDevice device, const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle);
typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandlePropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, HANDLE handle, VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleKHR(
VkDevice device,
const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo,
HANDLE* pHandle);
VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandlePropertiesKHR(
VkDevice device,
VkExternalMemoryHandleTypeFlagBits handleType,
HANDLE handle,
VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties);
#endif
#define VK_KHR_win32_keyed_mutex 1
#define VK_KHR_WIN32_KEYED_MUTEX_SPEC_VERSION 1
#define VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_KHR_win32_keyed_mutex"
typedef struct VkWin32KeyedMutexAcquireReleaseInfoKHR {
VkStructureType sType;
const void* pNext;
uint32_t acquireCount;
const VkDeviceMemory* pAcquireSyncs;
const uint64_t* pAcquireKeys;
const uint32_t* pAcquireTimeouts;
uint32_t releaseCount;
const VkDeviceMemory* pReleaseSyncs;
const uint64_t* pReleaseKeys;
} VkWin32KeyedMutexAcquireReleaseInfoKHR;
#define VK_KHR_external_semaphore_win32 1
#define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION 1
#define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME "VK_KHR_external_semaphore_win32"
typedef struct VkImportSemaphoreWin32HandleInfoKHR {
VkStructureType sType;
const void* pNext;
VkSemaphore semaphore;
VkSemaphoreImportFlags flags;
VkExternalSemaphoreHandleTypeFlagBits handleType;
HANDLE handle;
LPCWSTR name;
} VkImportSemaphoreWin32HandleInfoKHR;
typedef struct VkExportSemaphoreWin32HandleInfoKHR {
VkStructureType sType;
const void* pNext;
const SECURITY_ATTRIBUTES* pAttributes;
DWORD dwAccess;
LPCWSTR name;
} VkExportSemaphoreWin32HandleInfoKHR;
typedef struct VkD3D12FenceSubmitInfoKHR {
VkStructureType sType;
const void* pNext;
uint32_t waitSemaphoreValuesCount;
const uint64_t* pWaitSemaphoreValues;
uint32_t signalSemaphoreValuesCount;
const uint64_t* pSignalSemaphoreValues;
} VkD3D12FenceSubmitInfoKHR;
typedef struct VkSemaphoreGetWin32HandleInfoKHR {
VkStructureType sType;
const void* pNext;
VkSemaphore semaphore;
VkExternalSemaphoreHandleTypeFlagBits handleType;
} VkSemaphoreGetWin32HandleInfoKHR;
typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreWin32HandleKHR)(VkDevice device, const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo);
typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreWin32HandleKHR)(VkDevice device, const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreWin32HandleKHR(
VkDevice device,
const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo);
VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreWin32HandleKHR(
VkDevice device,
const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo,
HANDLE* pHandle);
#endif
#define VK_KHR_external_fence_win32 1
#define VK_KHR_EXTERNAL_FENCE_WIN32_SPEC_VERSION 1
#define VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME "VK_KHR_external_fence_win32"
typedef struct VkImportFenceWin32HandleInfoKHR {
VkStructureType sType;
const void* pNext;
VkFence fence;
VkFenceImportFlags flags;
VkExternalFenceHandleTypeFlagBits handleType;
HANDLE handle;
LPCWSTR name;
} VkImportFenceWin32HandleInfoKHR;
typedef struct VkExportFenceWin32HandleInfoKHR {
VkStructureType sType;
const void* pNext;
const SECURITY_ATTRIBUTES* pAttributes;
DWORD dwAccess;
LPCWSTR name;
} VkExportFenceWin32HandleInfoKHR;
typedef struct VkFenceGetWin32HandleInfoKHR {
VkStructureType sType;
const void* pNext;
VkFence fence;
VkExternalFenceHandleTypeFlagBits handleType;
} VkFenceGetWin32HandleInfoKHR;
typedef VkResult (VKAPI_PTR *PFN_vkImportFenceWin32HandleKHR)(VkDevice device, const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo);
typedef VkResult (VKAPI_PTR *PFN_vkGetFenceWin32HandleKHR)(VkDevice device, const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo, HANDLE* pHandle);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkImportFenceWin32HandleKHR(
VkDevice device,
const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo);
VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceWin32HandleKHR(
VkDevice device,
const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo,
HANDLE* pHandle);
#endif
#define VK_NV_external_memory_win32 1
#define VK_NV_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
#define VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_NV_external_memory_win32"
typedef struct VkImportMemoryWin32HandleInfoNV {
VkStructureType sType;
const void* pNext;
VkExternalMemoryHandleTypeFlagsNV handleType;
HANDLE handle;
} VkImportMemoryWin32HandleInfoNV;
typedef struct VkExportMemoryWin32HandleInfoNV {
VkStructureType sType;
const void* pNext;
const SECURITY_ATTRIBUTES* pAttributes;
DWORD dwAccess;
} VkExportMemoryWin32HandleInfoNV;
typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleNV)(VkDevice device, VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagsNV handleType, HANDLE* pHandle);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleNV(
VkDevice device,
VkDeviceMemory memory,
VkExternalMemoryHandleTypeFlagsNV handleType,
HANDLE* pHandle);
#endif
#define VK_NV_win32_keyed_mutex 1
#define VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION 2
#define VK_NV_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_NV_win32_keyed_mutex"
typedef struct VkWin32KeyedMutexAcquireReleaseInfoNV {
VkStructureType sType;
const void* pNext;
uint32_t acquireCount;
const VkDeviceMemory* pAcquireSyncs;
const uint64_t* pAcquireKeys;
const uint32_t* pAcquireTimeoutMilliseconds;
uint32_t releaseCount;
const VkDeviceMemory* pReleaseSyncs;
const uint64_t* pReleaseKeys;
} VkWin32KeyedMutexAcquireReleaseInfoNV;
#define VK_EXT_full_screen_exclusive 1
#define VK_EXT_FULL_SCREEN_EXCLUSIVE_SPEC_VERSION 4
#define VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME "VK_EXT_full_screen_exclusive"
typedef enum VkFullScreenExclusiveEXT {
VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT = 0,
VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT = 1,
VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT = 2,
VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT = 3,
VK_FULL_SCREEN_EXCLUSIVE_MAX_ENUM_EXT = 0x7FFFFFFF
} VkFullScreenExclusiveEXT;
typedef struct VkSurfaceFullScreenExclusiveInfoEXT {
VkStructureType sType;
void* pNext;
VkFullScreenExclusiveEXT fullScreenExclusive;
} VkSurfaceFullScreenExclusiveInfoEXT;
typedef struct VkSurfaceCapabilitiesFullScreenExclusiveEXT {
VkStructureType sType;
void* pNext;
VkBool32 fullScreenExclusiveSupported;
} VkSurfaceCapabilitiesFullScreenExclusiveEXT;
typedef struct VkSurfaceFullScreenExclusiveWin32InfoEXT {
VkStructureType sType;
const void* pNext;
HMONITOR hmonitor;
} VkSurfaceFullScreenExclusiveWin32InfoEXT;
typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes);
typedef VkResult (VKAPI_PTR *PFN_vkAcquireFullScreenExclusiveModeEXT)(VkDevice device, VkSwapchainKHR swapchain);
typedef VkResult (VKAPI_PTR *PFN_vkReleaseFullScreenExclusiveModeEXT)(VkDevice device, VkSwapchainKHR swapchain);
typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModes2EXT)(VkDevice device, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkDeviceGroupPresentModeFlagsKHR* pModes);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModes2EXT(
VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
uint32_t* pPresentModeCount,
VkPresentModeKHR* pPresentModes);
VKAPI_ATTR VkResult VKAPI_CALL vkAcquireFullScreenExclusiveModeEXT(
VkDevice device,
VkSwapchainKHR swapchain);
VKAPI_ATTR VkResult VKAPI_CALL vkReleaseFullScreenExclusiveModeEXT(
VkDevice device,
VkSwapchainKHR swapchain);
VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModes2EXT(
VkDevice device,
const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
VkDeviceGroupPresentModeFlagsKHR* pModes);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,55 @@
#ifndef VULKAN_XCB_H_
#define VULKAN_XCB_H_ 1
/*
** Copyright (c) 2015-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/
#ifdef __cplusplus
extern "C" {
#endif
#define VK_KHR_xcb_surface 1
#define VK_KHR_XCB_SURFACE_SPEC_VERSION 6
#define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface"
typedef VkFlags VkXcbSurfaceCreateFlagsKHR;
typedef struct VkXcbSurfaceCreateInfoKHR {
VkStructureType sType;
const void* pNext;
VkXcbSurfaceCreateFlagsKHR flags;
xcb_connection_t* connection;
xcb_window_t window;
} VkXcbSurfaceCreateInfoKHR;
typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR(
VkInstance instance,
const VkXcbSurfaceCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface);
VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentationSupportKHR(
VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex,
xcb_connection_t* connection,
xcb_visualid_t visual_id);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,55 @@
#ifndef VULKAN_XLIB_H_
#define VULKAN_XLIB_H_ 1
/*
** Copyright (c) 2015-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/
#ifdef __cplusplus
extern "C" {
#endif
#define VK_KHR_xlib_surface 1
#define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6
#define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface"
typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
typedef struct VkXlibSurfaceCreateInfoKHR {
VkStructureType sType;
const void* pNext;
VkXlibSurfaceCreateFlagsKHR flags;
Display* dpy;
Window window;
} VkXlibSurfaceCreateInfoKHR;
typedef VkResult (VKAPI_PTR *PFN_vkCreateXlibSurfaceKHR)(VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display* dpy, VisualID visualID);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkCreateXlibSurfaceKHR(
VkInstance instance,
const VkXlibSurfaceCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface);
VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentationSupportKHR(
VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex,
Display* dpy,
VisualID visualID);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,45 @@
#ifndef VULKAN_XLIB_XRANDR_H_
#define VULKAN_XLIB_XRANDR_H_ 1
/*
** Copyright (c) 2015-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/
/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/
#ifdef __cplusplus
extern "C" {
#endif
#define VK_EXT_acquire_xlib_display 1
#define VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION 1
#define VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_xlib_display"
typedef VkResult (VKAPI_PTR *PFN_vkAcquireXlibDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, VkDisplayKHR display);
typedef VkResult (VKAPI_PTR *PFN_vkGetRandROutputDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, RROutput rrOutput, VkDisplayKHR* pDisplay);
#ifndef VK_NO_PROTOTYPES
VKAPI_ATTR VkResult VKAPI_CALL vkAcquireXlibDisplayEXT(
VkPhysicalDevice physicalDevice,
Display* dpy,
VkDisplayKHR display);
VKAPI_ATTR VkResult VKAPI_CALL vkGetRandROutputDisplayEXT(
VkPhysicalDevice physicalDevice,
Display* dpy,
RROutput rrOutput,
VkDisplayKHR* pDisplay);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,146 +1,198 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "DX10_Hook.h" #include "DX10_Hook.h"
#include "Windows_Hook.h" #include "Windows_Hook.h"
#include "../Renderer_Detector.h"
#include "../../dll/dll.h"
#ifdef EMU_OVERLAY
#include <imgui.h> #include <imgui.h>
#include <impls/windows/imgui_impl_dx10.h> #include <backends/imgui_impl_dx10.h>
DX10_Hook* DX10_Hook::_inst = nullptr; DX10_Hook* DX10_Hook::_inst = nullptr;
bool DX10_Hook::start_hook() template<typename T>
inline void SafeRelease(T*& pUnk)
{ {
bool res = true; if (pUnk != nullptr)
if (!hooked)
{ {
if (!Windows_Hook::Inst()->start_hook()) pUnk->Release();
pUnk = nullptr;
}
}
bool DX10_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
{
if (!_Hooked)
{
if (Present == nullptr || ResizeTarget == nullptr || ResizeBuffers == nullptr)
{
SPDLOG_WARN("Failed to hook DirectX 11: Rendering functions missing.");
return false;
}
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
return false; return false;
PRINT_DEBUG("Hooked DirectX 10\n"); _WindowsHooked = true;
hooked = true;
Renderer_Detector::Inst().renderer_found(this); SPDLOG_INFO("Hooked DirectX 10");
_Hooked = true;
BeginHook(); BeginHook();
HookFuncs( HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)DX10_Hook::Present, &DX10_Hook::MyPresent), std::make_pair<void**, void*>(&(PVOID&)Present , &DX10_Hook::MyPresent),
std::make_pair<void**, void*>(&(PVOID&)DX10_Hook::ResizeTarget, &DX10_Hook::MyResizeTarget), std::make_pair<void**, void*>(&(PVOID&)ResizeTarget , &DX10_Hook::MyResizeTarget),
std::make_pair<void**, void*>(&(PVOID&)DX10_Hook::ResizeBuffers, &DX10_Hook::MyResizeBuffers) std::make_pair<void**, void*>(&(PVOID&)ResizeBuffers, &DX10_Hook::MyResizeBuffers)
); );
if (Present1 != nullptr)
{
HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)Present1, &DX10_Hook::MyPresent1)
);
}
EndHook(); EndHook();
get_steam_client()->steam_overlay->HookReady();
} }
return res; return true;
} }
void DX10_Hook::resetRenderState() bool DX10_Hook::IsStarted()
{ {
if (initialized) return _Hooked;
}
void DX10_Hook::_ResetRenderState()
{
if (_Initialized)
{ {
mainRenderTargetView->Release(); OverlayHookReady(false);
ImGui_ImplDX10_Shutdown(); ImGui_ImplDX10_Shutdown();
Windows_Hook::Inst()->resetRenderState(); Windows_Hook::Inst()->_ResetRenderState();
ImGui::DestroyContext(); ImGui::DestroyContext();
initialized = false; SafeRelease(mainRenderTargetView);
SafeRelease(pDevice);
_Initialized = false;
} }
} }
// Try to make this function and overlay's proc as short as possible or it might affect game's fps. // Try to make this function and overlay's proc as short as possible or it might affect game's fps.
void DX10_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain) void DX10_Hook::_PrepareForOverlay(IDXGISwapChain* pSwapChain)
{ {
DXGI_SWAP_CHAIN_DESC desc; DXGI_SWAP_CHAIN_DESC desc;
pSwapChain->GetDesc(&desc); pSwapChain->GetDesc(&desc);
if (!initialized) if (!_Initialized)
{ {
if (FAILED(pSwapChain->GetDevice(IID_PPV_ARGS(&pDevice)))) if (FAILED(pSwapChain->GetDevice(IID_PPV_ARGS(&pDevice))))
return; return;
ImGui::CreateContext(); ID3D10Texture2D* pBackBuffer = nullptr;
ImGuiIO& io = ImGui::GetIO();
io.IniFilename = NULL;
ID3D10Texture2D* pBackBuffer;
pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
pDevice->CreateRenderTargetView(pBackBuffer, NULL, &mainRenderTargetView); if (pBackBuffer == nullptr)
{
pDevice->Release();
return;
}
pDevice->CreateRenderTargetView(pBackBuffer, nullptr, &mainRenderTargetView);
pBackBuffer->Release(); pBackBuffer->Release();
ImGui::CreateContext();
ImGui_ImplDX10_Init(pDevice); ImGui_ImplDX10_Init(pDevice);
pDevice->Release(); _Initialized = true;
OverlayHookReady(true);
get_steam_client()->steam_overlay->CreateFonts();
initialized = true;
} }
if (ImGui_ImplDX10_NewFrame()) if (ImGui_ImplDX10_NewFrame() && Windows_Hook::Inst()->_PrepareForOverlay(desc.OutputWindow))
{ {
Windows_Hook::Inst()->prepareForOverlay(desc.OutputWindow);
ImGui::NewFrame(); ImGui::NewFrame();
get_steam_client()->steam_overlay->OverlayProc(); OverlayProc();
ImGui::Render(); ImGui::Render();
pDevice->OMSetRenderTargets(1, &mainRenderTargetView, NULL); pDevice->OMSetRenderTargets(1, &mainRenderTargetView, nullptr);
ImGui_ImplDX10_RenderDrawData(ImGui::GetDrawData()); ImGui_ImplDX10_RenderDrawData(ImGui::GetDrawData());
} }
} }
HRESULT STDMETHODCALLTYPE DX10_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags) HRESULT STDMETHODCALLTYPE DX10_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags)
{ {
DX10_Hook::Inst()->prepareForOverlay(_this); auto inst= DX10_Hook::Inst();
return (_this->*DX10_Hook::Inst()->Present)(SyncInterval, Flags); inst->_PrepareForOverlay(_this);
return (_this->*inst->Present)(SyncInterval, Flags);
} }
HRESULT STDMETHODCALLTYPE DX10_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters) HRESULT STDMETHODCALLTYPE DX10_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters)
{ {
DX10_Hook::Inst()->resetRenderState(); auto inst= DX10_Hook::Inst();
return (_this->*DX10_Hook::Inst()->ResizeTarget)(pNewTargetParameters); inst->_ResetRenderState();
return (_this->*inst->ResizeTarget)(pNewTargetParameters);
} }
HRESULT STDMETHODCALLTYPE DX10_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) HRESULT STDMETHODCALLTYPE DX10_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags)
{ {
DX10_Hook::Inst()->resetRenderState(); auto inst= DX10_Hook::Inst();
return (_this->*DX10_Hook::Inst()->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags); inst->_ResetRenderState();
return (_this->*inst->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags);
}
HRESULT STDMETHODCALLTYPE DX10_Hook::MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters)
{
auto inst = DX10_Hook::Inst();
inst->_PrepareForOverlay(_this);
return (_this->*inst->Present1)(SyncInterval, Flags, pPresentParameters);
} }
DX10_Hook::DX10_Hook(): DX10_Hook::DX10_Hook():
initialized(false), _Initialized(false),
hooked(false), _Hooked(false),
_WindowsHooked(false),
pDevice(nullptr), pDevice(nullptr),
mainRenderTargetView(nullptr), mainRenderTargetView(nullptr),
Present(nullptr), Present(nullptr),
ResizeBuffers(nullptr), ResizeBuffers(nullptr),
ResizeTarget(nullptr) ResizeTarget(nullptr),
Present1(nullptr)
{ {
_library = LoadLibrary(DX10_DLL);
} }
DX10_Hook::~DX10_Hook() DX10_Hook::~DX10_Hook()
{ {
PRINT_DEBUG("DX10 Hook removed\n"); //SPDLOG_INFO("DX10 Hook removed");
if (initialized) if (_WindowsHooked)
delete Windows_Hook::Inst();
if (_Initialized)
{ {
mainRenderTargetView->Release(); mainRenderTargetView->Release();
ImGui_ImplDX10_InvalidateDeviceObjects(); ImGui_ImplDX10_InvalidateDeviceObjects();
ImGui::DestroyContext(); ImGui::DestroyContext();
initialized = false; _Initialized = false;
} }
FreeLibrary(reinterpret_cast<HMODULE>(_library));
_inst = nullptr; _inst = nullptr;
} }
@ -152,21 +204,85 @@ DX10_Hook* DX10_Hook::Inst()
return _inst; return _inst;
} }
const char* DX10_Hook::get_lib_name() const std::string DX10_Hook::GetLibraryName() const
{ {
return DX10_DLL; return LibraryName;
} }
void DX10_Hook::loadFunctions(IDXGISwapChain *pSwapChain) void DX10_Hook::LoadFunctions(
decltype(Present) PresentFcn,
decltype(ResizeBuffers) ResizeBuffersFcn,
decltype(ResizeTarget) ResizeTargetFcn,
decltype(Present1) Present1Fcn)
{ {
void** vTable; Present = PresentFcn;
ResizeBuffers = ResizeBuffersFcn;
vTable = *reinterpret_cast<void***>(pSwapChain); ResizeTarget = ResizeTargetFcn;
#define LOAD_FUNC(X) (void*&)X = vTable[(int)IDXGISwapChainVTable::X] Present1 = Present1Fcn;
LOAD_FUNC(Present);
LOAD_FUNC(ResizeBuffers);
LOAD_FUNC(ResizeTarget);
#undef LOAD_FUNC
} }
#endif//EMU_OVERLAY std::weak_ptr<uint64_t> DX10_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
{
ID3D10ShaderResourceView** resource = new ID3D10ShaderResourceView*(nullptr);
// Create texture
D3D10_TEXTURE2D_DESC desc = {};
desc.Width = static_cast<UINT>(width);
desc.Height = static_cast<UINT>(height);
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D10_USAGE_DEFAULT;
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
ID3D10Texture2D* pTexture = nullptr;
D3D10_SUBRESOURCE_DATA subResource;
subResource.pSysMem = image_data;
subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0;
pDevice->CreateTexture2D(&desc, &subResource, &pTexture);
if (pTexture != nullptr)
{
// Create texture view
D3D10_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
pDevice->CreateShaderResourceView(pTexture, &srvDesc, resource);
// Release Texure, the shader resource increases the reference count.
pTexture->Release();
}
if (*resource == nullptr)
return std::shared_ptr<uint64_t>();
auto ptr = std::shared_ptr<uint64_t>((uint64_t*)resource, [](uint64_t* handle)
{
if (handle != nullptr)
{
ID3D10ShaderResourceView** resource = reinterpret_cast<ID3D10ShaderResourceView**>(handle);
(*resource)->Release();
delete resource;
}
});
_ImageResources.emplace(ptr);
return ptr;
}
void DX10_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
{
auto ptr = resource.lock();
if (ptr)
{
auto it = _ImageResources.find(ptr);
if (it != _ImageResources.end())
_ImageResources.erase(it);
}
}

View File

@ -1,51 +1,80 @@
#ifndef __INCLUDED_DX10_HOOK_H__ /*
#define __INCLUDED_DX10_HOOK_H__ * Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "../Base_Hook.h" #pragma once
#ifdef EMU_OVERLAY
#include "../internal_includes.h"
#include <d3d10.h> #include <d3d10.h>
#include "DirectX_VTables.h" #include <dxgi1_2.h>
class DX10_Hook : public Base_Hook class DX10_Hook :
public Renderer_Hook,
public Base_Hook
{ {
public: public:
#define DX10_DLL "d3d10.dll" static constexpr const char *DLL_NAME = "d3d10.dll";
private: private:
static DX10_Hook* _inst; static DX10_Hook* _inst;
// Variables // Variables
bool hooked; bool _Hooked;
bool initialized; bool _WindowsHooked;
bool _Initialized;
ID3D10Device* pDevice; ID3D10Device* pDevice;
ID3D10RenderTargetView* mainRenderTargetView; ID3D10RenderTargetView* mainRenderTargetView;
std::set<std::shared_ptr<uint64_t>> _ImageResources;
// Functions // Functions
DX10_Hook(); DX10_Hook();
void resetRenderState(); void _ResetRenderState();
void prepareForOverlay(IDXGISwapChain *pSwapChain); void _PrepareForOverlay(IDXGISwapChain *pSwapChain);
// Hook to render functions // Hook to render functions
static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags); static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags);
static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters); static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters);
static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags); static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags);
static HRESULT STDMETHODCALLTYPE MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters);
decltype(&IDXGISwapChain::Present) Present; decltype(&IDXGISwapChain::Present) Present;
decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers; decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers;
decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget; decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget;
decltype(&IDXGISwapChain1::Present1) Present1;
public: public:
std::string LibraryName;
virtual ~DX10_Hook(); virtual ~DX10_Hook();
bool start_hook(); virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
virtual bool IsStarted();
static DX10_Hook* Inst(); static DX10_Hook* Inst();
virtual const char* get_lib_name() const; virtual std::string GetLibraryName() const;
void loadFunctions(IDXGISwapChain *pSwapChain); void LoadFunctions(
decltype(Present) PresentFcn,
decltype(ResizeBuffers) ResizeBuffersFcn,
decltype(ResizeTarget) ResizeTargetFcn,
decltype(Present1) Present1Fcn);
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
}; };
#endif//EMU_OVERLAY
#endif//__INCLUDED_DX10_HOOK_H__

View File

@ -1,16 +1,41 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "DX11_Hook.h" #include "DX11_Hook.h"
#include "Windows_Hook.h" #include "Windows_Hook.h"
#include "../Renderer_Detector.h"
#include "../../dll/dll.h"
#ifdef EMU_OVERLAY
#include <imgui.h> #include <imgui.h>
#include <impls/windows/imgui_impl_dx11.h> #include <backends/imgui_impl_dx11.h>
DX11_Hook* DX11_Hook::_inst = nullptr; DX11_Hook* DX11_Hook::_inst = nullptr;
HRESULT GetDeviceAndCtxFromSwapchain(IDXGISwapChain* pSwapChain, ID3D11Device** ppDevice, ID3D11DeviceContext** ppContext) template<typename T>
inline void SafeRelease(T*& pUnk)
{
if (pUnk != nullptr)
{
pUnk->Release();
pUnk = nullptr;
}
}
static HRESULT GetDeviceAndCtxFromSwapchain(IDXGISwapChain* pSwapChain, ID3D11Device** ppDevice, ID3D11DeviceContext** ppContext)
{ {
HRESULT ret = pSwapChain->GetDevice(IID_PPV_ARGS(ppDevice)); HRESULT ret = pSwapChain->GetDevice(IID_PPV_ARGS(ppDevice));
@ -20,177 +45,192 @@ HRESULT GetDeviceAndCtxFromSwapchain(IDXGISwapChain* pSwapChain, ID3D11Device**
return ret; return ret;
} }
bool DX11_Hook::start_hook() bool DX11_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
{ {
bool res = true; if (!_Hooked)
if (!hooked)
{ {
if (!Windows_Hook::Inst()->start_hook()) if (Present == nullptr || ResizeTarget == nullptr || ResizeBuffers == nullptr)
{
SPDLOG_WARN("Failed to hook DirectX 11: Rendering functions missing.");
return false;
}
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
return false; return false;
PRINT_DEBUG("Hooked DirectX 11\n"); _WindowsHooked = true;
hooked = true;
Renderer_Detector::Inst().renderer_found(this); SPDLOG_INFO("Hooked DirectX 11");
_Hooked = true;
BeginHook(); BeginHook();
HookFuncs( HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)DX11_Hook::Present, &DX11_Hook::MyPresent), std::make_pair<void**, void*>(&(PVOID&)Present , &DX11_Hook::MyPresent),
std::make_pair<void**, void*>(&(PVOID&)DX11_Hook::ResizeTarget, &DX11_Hook::MyResizeTarget), std::make_pair<void**, void*>(&(PVOID&)ResizeTarget , &DX11_Hook::MyResizeTarget),
std::make_pair<void**, void*>(&(PVOID&)DX11_Hook::ResizeBuffers, &DX11_Hook::MyResizeBuffers) std::make_pair<void**, void*>(&(PVOID&)ResizeBuffers, &DX11_Hook::MyResizeBuffers)
); );
if (Present1 != nullptr)
{
HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)Present1, &DX11_Hook::MyPresent1)
);
}
EndHook(); EndHook();
get_steam_client()->steam_overlay->HookReady();
} }
return res; return true;
} }
void DX11_Hook::resetRenderState() bool DX11_Hook::IsStarted()
{ {
if (initialized) return _Hooked;
{ }
if (mainRenderTargetView) {
mainRenderTargetView->Release();
mainRenderTargetView = NULL;
}
pContext->Release(); void DX11_Hook::_ResetRenderState()
{
if (_Initialized)
{
OverlayHookReady(false);
ImGui_ImplDX11_Shutdown(); ImGui_ImplDX11_Shutdown();
Windows_Hook::Inst()->resetRenderState(); Windows_Hook::Inst()->_ResetRenderState();
ImGui::DestroyContext(); //ImGui::DestroyContext();
initialized = false; SafeRelease(mainRenderTargetView);
SafeRelease(pContext);
SafeRelease(pDevice);
_Initialized = false;
} }
} }
// Try to make this function and overlay's proc as short as possible or it might affect game's fps. // Try to make this function and overlay's proc as short as possible or it might affect game's fps.
void DX11_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain) void DX11_Hook::_PrepareForOverlay(IDXGISwapChain* pSwapChain)
{ {
DXGI_SWAP_CHAIN_DESC desc; DXGI_SWAP_CHAIN_DESC desc;
pSwapChain->GetDesc(&desc); pSwapChain->GetDesc(&desc);
if (!initialized) if (!_Initialized)
{ {
ID3D11Device* pDevice = nullptr; pDevice = nullptr;
if (FAILED(GetDeviceAndCtxFromSwapchain(pSwapChain, &pDevice, &pContext))) if (FAILED(GetDeviceAndCtxFromSwapchain(pSwapChain, &pDevice, &pContext)))
return; return;
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.IniFilename = NULL;
ID3D11Texture2D* pBackBuffer; ID3D11Texture2D* pBackBuffer;
pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
ID3D11RenderTargetView *get_targets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {}; pDevice->CreateRenderTargetView(pBackBuffer, NULL, &mainRenderTargetView);
pContext->OMGetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, get_targets, NULL);
bool bind_target = true;
for (unsigned i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) {
if (get_targets[i]) {
ID3D11Resource *res = NULL;
get_targets[i]->GetResource(&res);
if (res) {
if (res == (ID3D11Resource*)pBackBuffer) {
bind_target = false;
}
res->Release();
}
get_targets[i]->Release();
} else {
break;
}
}
if (bind_target) {
pDevice->CreateRenderTargetView(pBackBuffer, NULL, &mainRenderTargetView);
}
pBackBuffer->Release();
//ID3D11RenderTargetView* targets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {};
//pContext->OMGetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, targets, NULL);
//bool bind_target = true;
//
//for (unsigned i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT && targets[i] != nullptr; ++i)
//{
// ID3D11Resource* res = NULL;
// targets[i]->GetResource(&res);
// if (res)
// {
// if (res == (ID3D11Resource*)pBackBuffer)
// {
// pDevice->CreateRenderTargetView(pBackBuffer, NULL, &mainRenderTargetView);
// }
//
// res->Release();
// }
//
// targets[i]->Release();
//}
SafeRelease(pBackBuffer);
if (mainRenderTargetView == nullptr)
return;
if(ImGui::GetCurrentContext() == nullptr)
ImGui::CreateContext();
ImGui_ImplDX11_Init(pDevice, pContext); ImGui_ImplDX11_Init(pDevice, pContext);
pDevice->Release(); _Initialized = true;
OverlayHookReady(true);
get_steam_client()->steam_overlay->CreateFonts();
initialized = true;
} }
if (ImGui_ImplDX11_NewFrame()) if (ImGui_ImplDX11_NewFrame() && Windows_Hook::Inst()->_PrepareForOverlay(desc.OutputWindow))
{ {
Windows_Hook::Inst()->prepareForOverlay(desc.OutputWindow);
ImGui::NewFrame(); ImGui::NewFrame();
get_steam_client()->steam_overlay->OverlayProc(); OverlayProc();
ImGui::Render(); ImGui::Render();
if (mainRenderTargetView) { if (mainRenderTargetView)
{
pContext->OMSetRenderTargets(1, &mainRenderTargetView, NULL); pContext->OMSetRenderTargets(1, &mainRenderTargetView, NULL);
} }
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
} }
} }
HRESULT STDMETHODCALLTYPE DX11_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags) HRESULT STDMETHODCALLTYPE DX11_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags)
{ {
DX11_Hook::Inst()->prepareForOverlay(_this); auto inst = DX11_Hook::Inst();
inst->_PrepareForOverlay(_this);
return (_this->*DX11_Hook::Inst()->Present)(SyncInterval, Flags); return (_this->*inst->Present)(SyncInterval, Flags);
} }
HRESULT STDMETHODCALLTYPE DX11_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters) HRESULT STDMETHODCALLTYPE DX11_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters)
{ {
DX11_Hook::Inst()->resetRenderState(); auto inst = DX11_Hook::Inst();
return (_this->*DX11_Hook::Inst()->ResizeTarget)(pNewTargetParameters); inst->_ResetRenderState();
return (_this->*inst->ResizeTarget)(pNewTargetParameters);
} }
HRESULT STDMETHODCALLTYPE DX11_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) HRESULT STDMETHODCALLTYPE DX11_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags)
{ {
DX11_Hook::Inst()->resetRenderState(); auto inst = DX11_Hook::Inst();
return (_this->*DX11_Hook::Inst()->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags); inst->_ResetRenderState();
return (_this->*inst->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags);
}
HRESULT STDMETHODCALLTYPE DX11_Hook::MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters)
{
auto inst = DX11_Hook::Inst();
inst->_PrepareForOverlay(_this);
return (_this->*inst->Present1)(SyncInterval, Flags, pPresentParameters);
} }
DX11_Hook::DX11_Hook(): DX11_Hook::DX11_Hook():
initialized(false), _Initialized(false),
hooked(false), _Hooked(false),
_WindowsHooked(false),
pContext(nullptr), pContext(nullptr),
mainRenderTargetView(nullptr), mainRenderTargetView(nullptr),
Present(nullptr), Present(nullptr),
ResizeBuffers(nullptr), ResizeBuffers(nullptr),
ResizeTarget(nullptr) ResizeTarget(nullptr),
Present1(nullptr)
{ {
_library = LoadLibrary(DX11_DLL);
} }
DX11_Hook::~DX11_Hook() DX11_Hook::~DX11_Hook()
{ {
PRINT_DEBUG("DX11 Hook removed\n"); SPDLOG_INFO("DX11 Hook removed");
if (initialized) if (_WindowsHooked)
delete Windows_Hook::Inst();
if (_Initialized)
{ {
if (mainRenderTargetView) { SafeRelease(mainRenderTargetView);
mainRenderTargetView->Release(); SafeRelease(pContext);
mainRenderTargetView = NULL;
}
pContext->Release();
ImGui_ImplDX11_InvalidateDeviceObjects(); ImGui_ImplDX11_InvalidateDeviceObjects();
ImGui::DestroyContext(); ImGui::DestroyContext();
initialized = false; _Initialized = false;
} }
FreeLibrary(reinterpret_cast<HMODULE>(_library));
_inst = nullptr; _inst = nullptr;
} }
@ -202,21 +242,85 @@ DX11_Hook* DX11_Hook::Inst()
return _inst; return _inst;
} }
const char* DX11_Hook::get_lib_name() const std::string DX11_Hook::GetLibraryName() const
{ {
return DX11_DLL; return LibraryName;
} }
void DX11_Hook::loadFunctions(IDXGISwapChain *pSwapChain) void DX11_Hook::LoadFunctions(
decltype(Present) PresentFcn,
decltype(ResizeBuffers) ResizeBuffersFcn,
decltype(ResizeTarget) ResizeTargetFcn,
decltype(Present1) Present1Fcn)
{ {
void** vTable; Present = PresentFcn;
ResizeBuffers = ResizeBuffersFcn;
vTable = *reinterpret_cast<void***>(pSwapChain); ResizeTarget = ResizeTargetFcn;
#define LOAD_FUNC(X) (void*&)X = vTable[(int)IDXGISwapChainVTable::X] Present1 = Present1Fcn;
LOAD_FUNC(Present);
LOAD_FUNC(ResizeBuffers);
LOAD_FUNC(ResizeTarget);
#undef LOAD_FUNC
} }
#endif//EMU_OVERLAY std::weak_ptr<uint64_t> DX11_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
{
ID3D11ShaderResourceView** resource = new ID3D11ShaderResourceView*(nullptr);
// Create texture
D3D11_TEXTURE2D_DESC desc = {};
desc.Width = static_cast<UINT>(width);
desc.Height = static_cast<UINT>(height);
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
ID3D11Texture2D* pTexture = nullptr;
D3D11_SUBRESOURCE_DATA subResource;
subResource.pSysMem = image_data;
subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0;
pDevice->CreateTexture2D(&desc, &subResource, &pTexture);
if (pTexture != nullptr)
{
// Create texture view
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc{};
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
pDevice->CreateShaderResourceView(pTexture, &srvDesc, resource);
// Release Texture, the shader resource increases the reference count.
pTexture->Release();
}
if (*resource == nullptr)
return std::shared_ptr<uint64_t>();
auto ptr = std::shared_ptr<uint64_t>((uint64_t*)resource, [](uint64_t* handle)
{
if(handle != nullptr)
{
ID3D11ShaderResourceView** resource = reinterpret_cast<ID3D11ShaderResourceView**>(handle);
(*resource)->Release();
delete resource;
}
});
_ImageResources.emplace(ptr);
return ptr;
}
void DX11_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
{
auto ptr = resource.lock();
if (ptr)
{
auto it = _ImageResources.find(ptr);
if (it != _ImageResources.end())
_ImageResources.erase(it);
}
}

View File

@ -1,51 +1,81 @@
#ifndef __INCLUDED_DX11_HOOK_H__ /*
#define __INCLUDED_DX11_HOOK_H__ * Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "../Base_Hook.h" #pragma once
#ifdef EMU_OVERLAY
#include "../internal_includes.h"
#include <d3d11.h> #include <d3d11.h>
#include "DirectX_VTables.h" #include <dxgi1_2.h>
class DX11_Hook : public Base_Hook class DX11_Hook :
public Renderer_Hook,
public Base_Hook
{ {
public: public:
#define DX11_DLL "d3d11.dll" static constexpr const char *DLL_NAME = "d3d11.dll";
private: private:
static DX11_Hook* _inst; static DX11_Hook* _inst;
// Variables // Variables
bool hooked; bool _Hooked;
bool initialized; bool _WindowsHooked;
bool _Initialized;
ID3D11Device* pDevice;
ID3D11DeviceContext* pContext; ID3D11DeviceContext* pContext;
ID3D11RenderTargetView* mainRenderTargetView; ID3D11RenderTargetView* mainRenderTargetView;
std::set<std::shared_ptr<uint64_t>> _ImageResources;
// Functions // Functions
DX11_Hook(); DX11_Hook();
void resetRenderState(); void _ResetRenderState();
void prepareForOverlay(IDXGISwapChain* pSwapChain); void _PrepareForOverlay(IDXGISwapChain* pSwapChain);
// Hook to render functions // Hook to render functions
static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags); static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags);
static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters); static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters);
static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags); static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags);
static HRESULT STDMETHODCALLTYPE MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters);
decltype(&IDXGISwapChain::Present) Present; decltype(&IDXGISwapChain::Present) Present;
decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers; decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers;
decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget; decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget;
decltype(&IDXGISwapChain1::Present1) Present1;
public: public:
std::string LibraryName;
virtual ~DX11_Hook(); virtual ~DX11_Hook();
bool start_hook(); virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
virtual bool IsStarted();
static DX11_Hook* Inst(); static DX11_Hook* Inst();
virtual const char* get_lib_name() const; virtual std::string GetLibraryName() const;
void loadFunctions(IDXGISwapChain *pSwapChain); void LoadFunctions(
decltype(Present) PresentFcn,
decltype(ResizeBuffers) ResizeBuffersFcn,
decltype(ResizeTarget) ResizeTargetFcn,
decltype(Present1) Present1Fcn);
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
}; };
#endif//EMU_OVERLAY
#endif//__INCLUDED_DX11_HOOK_H__

View File

@ -1,74 +1,161 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "DX12_Hook.h" #include "DX12_Hook.h"
#include "Windows_Hook.h" #include "Windows_Hook.h"
#include "../Renderer_Detector.h"
#include "../../dll/dll.h"
#ifdef EMU_OVERLAY
#include <imgui.h> #include <imgui.h>
#include <impls/windows/imgui_impl_dx12.h> #include <backends/imgui_impl_dx12.h>
#include <dxgi1_4.h>
DX12_Hook* DX12_Hook::_inst = nullptr; DX12_Hook* DX12_Hook::_inst = nullptr;
bool DX12_Hook::start_hook() template<typename T>
inline void SafeRelease(T*& pUnk)
{ {
bool res = true; if (pUnk != nullptr)
if (!hooked)
{ {
if (!Windows_Hook::Inst()->start_hook()) pUnk->Release();
pUnk = nullptr;
}
}
bool DX12_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
{
if (!_Hooked)
{
if (Present == nullptr || ResizeTarget == nullptr || ResizeBuffers == nullptr || ExecuteCommandLists == nullptr)
{
SPDLOG_WARN("Failed to hook DirectX 12: Rendering functions missing.");
return false;
}
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
return false; return false;
PRINT_DEBUG("Hooked DirectX 12\n"); _WindowsHooked = true;
hooked = true;
Renderer_Detector::Inst().renderer_found(this); SPDLOG_INFO("Hooked DirectX 12");
_Hooked = true;
BeginHook(); BeginHook();
HookFuncs( HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)DX12_Hook::Present, &DX12_Hook::MyPresent), std::make_pair<void**, void*>(&(PVOID&)Present , &DX12_Hook::MyPresent),
std::make_pair<void**, void*>(&(PVOID&)DX12_Hook::ResizeTarget, &DX12_Hook::MyResizeTarget), std::make_pair<void**, void*>(&(PVOID&)ResizeTarget , &DX12_Hook::MyResizeTarget),
std::make_pair<void**, void*>(&(PVOID&)DX12_Hook::ResizeBuffers, &DX12_Hook::MyResizeBuffers), std::make_pair<void**, void*>(&(PVOID&)ResizeBuffers , &DX12_Hook::MyResizeBuffers),
std::make_pair<void**, void*>(&(PVOID&)DX12_Hook::ExecuteCommandLists, &DX12_Hook::MyExecuteCommandLists) std::make_pair<void**, void*>(&(PVOID&)ExecuteCommandLists, &DX12_Hook::MyExecuteCommandLists)
); );
if (Present1 != nullptr)
{
HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)Present1, &DX12_Hook::MyPresent1)
);
}
EndHook(); EndHook();
get_steam_client()->steam_overlay->HookReady();
} }
return res; return true;
} }
void DX12_Hook::resetRenderState() bool DX12_Hook::IsStarted()
{ {
if (initialized) return _Hooked;
}
//DX12_Hook::heap_t DX12_Hook::get_free_texture_heap()
//{
// int64_t i;
// std::vector<bool>::reference* free_heap;
// for (i = 0; i < srvDescHeapBitmap.size(); ++i)
// {
// if (!srvDescHeapBitmap[i])
// {
// srvDescHeapBitmap[i] = true;
// break;
// }
// }
//
// if (i == srvDescHeapBitmap.size())
// return heap_t{ {}, {}, -1 };
//
// UINT inc = pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
//
// return heap_t{
// pSrvDescHeap->GetGPUDescriptorHandleForHeapStart().ptr + inc * i,
// pSrvDescHeap->GetCPUDescriptorHandleForHeapStart().ptr + inc * i,
// i
// };
//}
//
//bool DX12_Hook::release_texture_heap(int64_t heap_id)
//{
// srvDescHeapBitmap[heap_id] = false;
// return true;
//}
ID3D12CommandQueue* DX12_Hook::_FindCommandQueueFromSwapChain(IDXGISwapChain* pSwapChain)
{
ID3D12CommandQueue* pCommandQueue = nullptr;
if (CommandQueueOffset == 0 && pCmdQueue != nullptr)
{ {
pSrvDescHeap->Release(); for (size_t i = 0; i < 1024; ++i)
for (UINT i = 0; i < bufferCount; ++i)
{ {
pCmdAlloc[i]->Release(); if (*reinterpret_cast<ID3D12CommandQueue**>(reinterpret_cast<uintptr_t>(pSwapChain) + i) == pCmdQueue)
pBackBuffer[i]->Release(); {
SPDLOG_INFO("Found IDXGISwapChain::ppCommandQueue at offset {}.", i);
CommandQueueOffset = i;
break;
}
} }
pRtvDescHeap->Release(); }
delete[]pCmdAlloc;
delete[]pBackBuffer; if (CommandQueueOffset != 0)
pCommandQueue = *reinterpret_cast<ID3D12CommandQueue**>(reinterpret_cast<uintptr_t>(pSwapChain) + CommandQueueOffset);
return pCommandQueue;
}
void DX12_Hook::_ResetRenderState()
{
if (_Initialized)
{
OverlayHookReady(false);
ImGui_ImplDX12_Shutdown(); ImGui_ImplDX12_Shutdown();
Windows_Hook::Inst()->resetRenderState(); Windows_Hook::Inst()->_ResetRenderState();
ImGui::DestroyContext(); ImGui::DestroyContext();
initialized = false; OverlayFrames.clear();
SafeRelease(pSrvDescHeap);
SafeRelease(pRtvDescHeap);
SafeRelease(pDevice);
_Initialized = false;
} }
} }
// Try to make this function and overlay's proc as short as possible or it might affect game's fps. // Try to make this function and overlay's proc as short as possible or it might affect game's fps.
void DX12_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain) void DX12_Hook::_PrepareForOverlay(IDXGISwapChain* pSwapChain, ID3D12CommandQueue* pCommandQueue)
{ {
if (pCmdQueue == nullptr) if (pCommandQueue == nullptr)
return; return;
ID3D12CommandQueue* pCmdQueue = this->pCmdQueue;
IDXGISwapChain3* pSwapChain3 = nullptr; IDXGISwapChain3* pSwapChain3 = nullptr;
DXGI_SWAP_CHAIN_DESC sc_desc; DXGI_SWAP_CHAIN_DESC sc_desc;
pSwapChain->QueryInterface(IID_PPV_ARGS(&pSwapChain3)); pSwapChain->QueryInterface(IID_PPV_ARGS(&pSwapChain3));
@ -77,21 +164,24 @@ void DX12_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain)
pSwapChain3->GetDesc(&sc_desc); pSwapChain3->GetDesc(&sc_desc);
if (!initialized) if (!_Initialized)
{ {
UINT bufferIndex = pSwapChain3->GetCurrentBackBufferIndex(); UINT bufferIndex = pSwapChain3->GetCurrentBackBufferIndex();
ID3D12Device* pDevice; pDevice = nullptr;
if (pSwapChain3->GetDevice(IID_PPV_ARGS(&pDevice)) != S_OK) if (pSwapChain3->GetDevice(IID_PPV_ARGS(&pDevice)) != S_OK)
return; return;
bufferCount = sc_desc.BufferCount; UINT bufferCount = sc_desc.BufferCount;
mainRenderTargets.clear(); //srvDescHeapBitmap.clear();
//constexpr UINT descriptor_count = 1024;
{ {
D3D12_DESCRIPTOR_HEAP_DESC desc = {}; D3D12_DESCRIPTOR_HEAP_DESC desc = {};
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
desc.NumDescriptors = 1; desc.NumDescriptors = 1;
//desc.NumDescriptors = descriptor_count;
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
if (pDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&pSrvDescHeap)) != S_OK) if (pDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&pSrvDescHeap)) != S_OK)
{ {
@ -100,6 +190,9 @@ void DX12_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain)
return; return;
} }
} }
//srvDescHeapBitmap.resize(descriptor_count, false);
{ {
D3D12_DESCRIPTOR_HEAP_DESC desc = {}; D3D12_DESCRIPTOR_HEAP_DESC desc = {};
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
@ -116,88 +209,92 @@ void DX12_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain)
SIZE_T rtvDescriptorSize = pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); SIZE_T rtvDescriptorSize = pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = pRtvDescHeap->GetCPUDescriptorHandleForHeapStart(); D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = pRtvDescHeap->GetCPUDescriptorHandleForHeapStart();
pCmdAlloc = new ID3D12CommandAllocator * [bufferCount]; ID3D12CommandAllocator* pCmdAlloc;
for (int i = 0; i < bufferCount; ++i) ID3D12Resource* pBackBuffer;
for (UINT i = 0; i < bufferCount; ++i)
{ {
mainRenderTargets.push_back(rtvHandle); pCmdAlloc = nullptr;
pBackBuffer = nullptr;
if (pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&pCmdAlloc)) != S_OK || pCmdAlloc == nullptr)
{
OverlayFrames.clear();
pSrvDescHeap->Release();
pRtvDescHeap->Release();
pDevice->Release();
pSwapChain3->Release();
return;
}
if (i == 0)
{
if (pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, pCmdAlloc, NULL, IID_PPV_ARGS(&pCmdList)) != S_OK ||
pCmdList == nullptr || pCmdList->Close() != S_OK)
{
OverlayFrames.clear();
SafeRelease(pCmdList);
pCmdAlloc->Release();
pSrvDescHeap->Release();
pRtvDescHeap->Release();
pDevice->Release();
pSwapChain3->Release();
return;
}
}
if (pSwapChain3->GetBuffer(i, IID_PPV_ARGS(&pBackBuffer)) != S_OK || pBackBuffer == nullptr)
{
OverlayFrames.clear();
pCmdList->Release();
pCmdAlloc->Release();
pSrvDescHeap->Release();
pRtvDescHeap->Release();
pDevice->Release();
pSwapChain3->Release();
return;
}
pDevice->CreateRenderTargetView(pBackBuffer, NULL, rtvHandle);
OverlayFrames.emplace_back(rtvHandle, pCmdAlloc, pBackBuffer);
rtvHandle.ptr += rtvDescriptorSize; rtvHandle.ptr += rtvDescriptorSize;
} }
} }
for (UINT i = 0; i < sc_desc.BufferCount; ++i)
{
if (pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&pCmdAlloc[i])) != S_OK)
{
pDevice->Release();
pSwapChain3->Release();
pSrvDescHeap->Release();
for (UINT j = 0; j < i; ++j)
{
pCmdAlloc[j]->Release();
}
pRtvDescHeap->Release();
delete[]pCmdAlloc;
return;
}
}
if (pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, pCmdAlloc[0], NULL, IID_PPV_ARGS(&pCmdList)) != S_OK || //auto heaps = std::move(get_free_texture_heap());
pCmdList->Close() != S_OK)
{
pDevice->Release();
pSwapChain3->Release();
pSrvDescHeap->Release();
for (UINT i = 0; i < bufferCount; ++i)
pCmdAlloc[i]->Release();
pRtvDescHeap->Release();
delete[]pCmdAlloc;
return;
}
pBackBuffer = new ID3D12Resource * [bufferCount];
for (UINT i = 0; i < bufferCount; i++)
{
pSwapChain3->GetBuffer(i, IID_PPV_ARGS(&pBackBuffer[i]));
pDevice->CreateRenderTargetView(pBackBuffer[i], NULL, mainRenderTargets[i]);
}
ImGui::CreateContext(); ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); ImGui_ImplDX12_Init(pDevice, bufferCount, DXGI_FORMAT_R8G8B8A8_UNORM, pSrvDescHeap,
io.IniFilename = NULL;
ImGui_ImplDX12_Init(pDevice, bufferCount, DXGI_FORMAT_R8G8B8A8_UNORM, NULL,
pSrvDescHeap->GetCPUDescriptorHandleForHeapStart(), pSrvDescHeap->GetCPUDescriptorHandleForHeapStart(),
pSrvDescHeap->GetGPUDescriptorHandleForHeapStart()); pSrvDescHeap->GetGPUDescriptorHandleForHeapStart());
//heaps.cpu_handle,
//heaps.gpu_handle);
get_steam_client()->steam_overlay->CreateFonts(); _Initialized = true;
OverlayHookReady(true);
initialized = true;
pDevice->Release();
} }
if (ImGui_ImplDX12_NewFrame())
{
Windows_Hook::Inst()->prepareForOverlay(sc_desc.OutputWindow);
if (ImGui_ImplDX12_NewFrame() && Windows_Hook::Inst()->_PrepareForOverlay(sc_desc.OutputWindow))
{
ImGui::NewFrame(); ImGui::NewFrame();
get_steam_client()->steam_overlay->OverlayProc(); OverlayProc();
UINT bufferIndex = pSwapChain3->GetCurrentBackBufferIndex(); UINT bufferIndex = pSwapChain3->GetCurrentBackBufferIndex();
D3D12_RESOURCE_BARRIER barrier = {}; D3D12_RESOURCE_BARRIER barrier = {};
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = pBackBuffer[bufferIndex]; barrier.Transition.pResource = OverlayFrames[bufferIndex].pBackBuffer;
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
pCmdAlloc[bufferIndex]->Reset(); OverlayFrames[bufferIndex].pCmdAlloc->Reset();
pCmdList->Reset(pCmdAlloc[bufferIndex], NULL); pCmdList->Reset(OverlayFrames[bufferIndex].pCmdAlloc, NULL);
pCmdList->ResourceBarrier(1, &barrier); pCmdList->ResourceBarrier(1, &barrier);
pCmdList->OMSetRenderTargets(1, &mainRenderTargets[bufferIndex], FALSE, NULL); pCmdList->OMSetRenderTargets(1, &OverlayFrames[bufferIndex].RenderTarget, FALSE, NULL);
pCmdList->SetDescriptorHeaps(1, &pSrvDescHeap); pCmdList->SetDescriptorHeaps(1, &pSrvDescHeap);
ImGui::Render(); ImGui::Render();
@ -208,81 +305,98 @@ void DX12_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain)
pCmdList->ResourceBarrier(1, &barrier); pCmdList->ResourceBarrier(1, &barrier);
pCmdList->Close(); pCmdList->Close();
pCmdQueue->ExecuteCommandLists(1, (ID3D12CommandList**)&pCmdList); pCommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&pCmdList);
} }
pSwapChain3->Release(); pSwapChain3->Release();
} }
HRESULT STDMETHODCALLTYPE DX12_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags) HRESULT STDMETHODCALLTYPE DX12_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags)
{ {
DX12_Hook::Inst()->prepareForOverlay(_this); auto inst = DX12_Hook::Inst();
return (_this->*DX12_Hook::Inst()->Present)(SyncInterval, Flags); ID3D12CommandQueue* pCommandQueue = inst->_FindCommandQueueFromSwapChain(_this);
if (pCommandQueue != nullptr)
{
inst->_PrepareForOverlay(_this, pCommandQueue);
}
return (_this->*inst->Present)(SyncInterval, Flags);
} }
HRESULT STDMETHODCALLTYPE DX12_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters) HRESULT STDMETHODCALLTYPE DX12_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters)
{ {
DX12_Hook::Inst()->resetRenderState(); auto inst = DX12_Hook::Inst();
return (_this->*DX12_Hook::Inst()->ResizeTarget)(pNewTargetParameters); inst->_ResetRenderState();
return (_this->*inst->ResizeTarget)(pNewTargetParameters);
} }
HRESULT STDMETHODCALLTYPE DX12_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) HRESULT STDMETHODCALLTYPE DX12_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags)
{ {
DX12_Hook::Inst()->resetRenderState(); auto inst = DX12_Hook::Inst();
return (_this->*DX12_Hook::Inst()->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags); inst->_ResetRenderState();
return (_this->*inst->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags);
} }
void STDMETHODCALLTYPE DX12_Hook::MyExecuteCommandLists(ID3D12CommandQueue *_this, UINT NumCommandLists, ID3D12CommandList* const* ppCommandLists) void STDMETHODCALLTYPE DX12_Hook::MyExecuteCommandLists(ID3D12CommandQueue *_this, UINT NumCommandLists, ID3D12CommandList* const* ppCommandLists)
{ {
DX12_Hook* me = DX12_Hook::Inst(); auto inst = DX12_Hook::Inst();
me->pCmdQueue = _this; inst->pCmdQueue = _this;
(_this->*inst->ExecuteCommandLists)(NumCommandLists, ppCommandLists);
}
(_this->*DX12_Hook::Inst()->ExecuteCommandLists)(NumCommandLists, ppCommandLists); HRESULT STDMETHODCALLTYPE DX12_Hook::MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters)
{
auto inst = DX12_Hook::Inst();
ID3D12CommandQueue* pCommandQueue = inst->_FindCommandQueueFromSwapChain(_this);
if (pCommandQueue != nullptr)
{
inst->_PrepareForOverlay(_this, pCommandQueue);
}
return (_this->*inst->Present1)(SyncInterval, Flags, pPresentParameters);
} }
DX12_Hook::DX12_Hook(): DX12_Hook::DX12_Hook():
initialized(false), _Initialized(false),
CommandQueueOffset(0),
pDevice(nullptr),
pCmdQueue(nullptr), pCmdQueue(nullptr),
bufferCount(0),
pCmdAlloc(nullptr),
pSrvDescHeap(nullptr), pSrvDescHeap(nullptr),
pCmdList(nullptr), pCmdList(nullptr),
pRtvDescHeap(nullptr), pRtvDescHeap(nullptr),
hooked(false), _Hooked(false),
_WindowsHooked(false),
Present(nullptr), Present(nullptr),
ResizeBuffers(nullptr), ResizeBuffers(nullptr),
ResizeTarget(nullptr), ResizeTarget(nullptr),
ExecuteCommandLists(nullptr) ExecuteCommandLists(nullptr),
Present1(nullptr)
{ {
_library = LoadLibrary(DX12_DLL); SPDLOG_WARN("DX12 support is experimental, don't complain if it doesn't work as expected.");
PRINT_DEBUG("DX12 support is experimental, don't complain if it doesn't work as expected.\n");
} }
DX12_Hook::~DX12_Hook() DX12_Hook::~DX12_Hook()
{ {
PRINT_DEBUG("DX12 Hook removed\n"); SPDLOG_INFO("DX12 Hook removed");
if (initialized) if (_WindowsHooked)
delete Windows_Hook::Inst();
if (_Initialized)
{ {
OverlayFrames.clear();
pSrvDescHeap->Release(); pSrvDescHeap->Release();
for (UINT i = 0; i < bufferCount; ++i)
{
pCmdAlloc[i]->Release();
pBackBuffer[i]->Release();
}
pRtvDescHeap->Release(); pRtvDescHeap->Release();
delete[]pCmdAlloc;
delete[]pBackBuffer;
ImGui_ImplDX12_InvalidateDeviceObjects(); ImGui_ImplDX12_InvalidateDeviceObjects();
ImGui::DestroyContext(); ImGui::DestroyContext();
initialized = false; _Initialized = false;
} }
FreeLibrary(reinterpret_cast<HMODULE>(_library));
_inst = nullptr; _inst = nullptr;
} }
@ -294,26 +408,204 @@ DX12_Hook* DX12_Hook::Inst()
return _inst; return _inst;
} }
const char* DX12_Hook::get_lib_name() const std::string DX12_Hook::GetLibraryName() const
{ {
return DX12_DLL; return LibraryName;
} }
void DX12_Hook::loadFunctions(ID3D12CommandQueue* pCommandQueue, IDXGISwapChain *pSwapChain) void DX12_Hook::LoadFunctions(
decltype(Present) PresentFcn,
decltype(ResizeBuffers) ResizeBuffersFcn,
decltype(ResizeTarget) ResizeTargetFcn,
decltype(ExecuteCommandLists) ExecuteCommandListsFcn,
decltype(Present1) Present1Fcn)
{ {
void** vTable; Present = PresentFcn;
ResizeBuffers = ResizeBuffersFcn;
vTable = *reinterpret_cast<void***>(pCommandQueue); ResizeTarget = ResizeTargetFcn;
#define LOAD_FUNC(X) (void*&)X = vTable[(int)ID3D12CommandQueueVTable::X]
LOAD_FUNC(ExecuteCommandLists);
#undef LOAD_FUNC
vTable = *reinterpret_cast<void***>(pSwapChain); ExecuteCommandLists = ExecuteCommandListsFcn;
#define LOAD_FUNC(X) (void*&)X = vTable[(int)IDXGISwapChainVTable::X]
LOAD_FUNC(Present); Present1 = Present1Fcn;
LOAD_FUNC(ResizeBuffers);
LOAD_FUNC(ResizeTarget);
#undef LOAD_FUNC
} }
#endif//EMU_OVERLAY std::weak_ptr<uint64_t> DX12_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
{
return std::shared_ptr<uint64_t>();
//heap_t heap = get_free_texture_heap();
//
//if (heap.id == -1)
// return nullptr;
//
//HRESULT hr;
//
//D3D12_HEAP_PROPERTIES props;
//memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
//props.Type = D3D12_HEAP_TYPE_DEFAULT;
//props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
//props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
//
//D3D12_RESOURCE_DESC desc;
//ZeroMemory(&desc, sizeof(desc));
//desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
//desc.Alignment = 0;
//desc.Width = source->width();
//desc.Height = source->height();
//desc.DepthOrArraySize = 1;
//desc.MipLevels = 1;
//desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
//desc.SampleDesc.Count = 1;
//desc.SampleDesc.Quality = 0;
//desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
//desc.Flags = D3D12_RESOURCE_FLAG_NONE;
//
//ID3D12Resource* pTexture = NULL;
//pDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
// D3D12_RESOURCE_STATE_COPY_DEST, NULL, IID_PPV_ARGS(&pTexture));
//
//UINT uploadPitch = (source->width() * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u);
//UINT uploadSize = source->height() * uploadPitch;
//desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
//desc.Alignment = 0;
//desc.Width = uploadSize;
//desc.Height = 1;
//desc.DepthOrArraySize = 1;
//desc.MipLevels = 1;
//desc.Format = DXGI_FORMAT_UNKNOWN;
//desc.SampleDesc.Count = 1;
//desc.SampleDesc.Quality = 0;
//desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
//desc.Flags = D3D12_RESOURCE_FLAG_NONE;
//
//props.Type = D3D12_HEAP_TYPE_UPLOAD;
//props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
//props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
//
//ID3D12Resource* uploadBuffer = NULL;
//hr = pDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
// D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&uploadBuffer));
//IM_ASSERT(SUCCEEDED(hr));
//
//void* mapped = NULL;
//D3D12_RANGE range = { 0, uploadSize };
//hr = uploadBuffer->Map(0, &range, &mapped);
//IM_ASSERT(SUCCEEDED(hr));
//for (int y = 0; y < source->height(); y++)
// memcpy((void*)((uintptr_t)mapped + y * uploadPitch), reinterpret_cast<uint8_t*>(source->get_raw_pointer()) + y * source->width() * 4, source->width() * 4);
//uploadBuffer->Unmap(0, &range);
//
//D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
//srcLocation.pResource = uploadBuffer;
//srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
//srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
//srcLocation.PlacedFootprint.Footprint.Width = source->width();
//srcLocation.PlacedFootprint.Footprint.Height = source->height();
//srcLocation.PlacedFootprint.Footprint.Depth = 1;
//srcLocation.PlacedFootprint.Footprint.RowPitch = uploadPitch;
//
//D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
//dstLocation.pResource = pTexture;
//dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
//dstLocation.SubresourceIndex = 0;
//
//D3D12_RESOURCE_BARRIER barrier = {};
//barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
//barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
//barrier.Transition.pResource = pTexture;
//barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
//barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
//barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
//
//ID3D12Fence* fence = NULL;
//hr = pDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
//IM_ASSERT(SUCCEEDED(hr));
//
//HANDLE event = CreateEvent(0, 0, 0, 0);
//IM_ASSERT(event != NULL);
//
//D3D12_COMMAND_QUEUE_DESC queueDesc = {};
//queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
//queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
//queueDesc.NodeMask = 1;
//
//ID3D12CommandQueue* cmdQueue = NULL;
//hr = pDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&cmdQueue));
//IM_ASSERT(SUCCEEDED(hr));
//
//ID3D12CommandAllocator* cmdAlloc = NULL;
//hr = pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc));
//IM_ASSERT(SUCCEEDED(hr));
//
//ID3D12GraphicsCommandList* cmdList = NULL;
//hr = pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, NULL, IID_PPV_ARGS(&cmdList));
//IM_ASSERT(SUCCEEDED(hr));
//
//cmdList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, NULL);
//cmdList->ResourceBarrier(1, &barrier);
//
//hr = cmdList->Close();
//IM_ASSERT(SUCCEEDED(hr));
//
//cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList);
//hr = cmdQueue->Signal(fence, 1);
//IM_ASSERT(SUCCEEDED(hr));
//
//fence->SetEventOnCompletion(1, event);
//WaitForSingleObject(event, INFINITE);
//
//cmdList->Release();
//cmdAlloc->Release();
//cmdQueue->Release();
//CloseHandle(event);
//fence->Release();
//uploadBuffer->Release();
//
//// Create texture view
//D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
//ZeroMemory(&srvDesc, sizeof(srvDesc));
//srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
//srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
//srvDesc.Texture2D.MipLevels = desc.MipLevels;
//srvDesc.Texture2D.MostDetailedMip = 0;
//srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
//
//pDevice->CreateShaderResourceView(pTexture, &srvDesc, heap.cpu_handle);
//
////pSrvDescHeap->Release();
////pTexture->Release();
//
//using gpu_heap_t = decltype(D3D12_GPU_DESCRIPTOR_HANDLE::ptr);
//struct texture_t{
// gpu_heap_t gpu_handle; // This must be the first member, ImGui will use the content of the pointer as a D3D12_GPU_DESCRIPTOR_HANDLE::ptr
// ID3D12Resource* pTexture;
// int64_t heap_id;
//};
//
//texture_t* texture_data = new texture_t;
//texture_data->gpu_handle = heap.gpu_handle.ptr;
//texture_data->pTexture = pTexture;
//texture_data->heap_id = heap.id;
//
//return std::shared_ptr<uint64_t>((uint64_t*)texture_data, [this](uint64_t* handle)
//{
// if (handle != nullptr)
// {
// texture_t* pTextureData = reinterpret_cast<texture_t*>(handle);
// pTextureData->pTexture->Release();
// release_texture_heap(pTextureData->heap_id);
//
// delete pTextureData;
// }
//});
}
void DX12_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
{
//auto ptr = resource.lock();
//if (ptr)
//{
// auto it = _ImageResources.find(ptr);
// if (it != _ImageResources.end())
// _ImageResources.erase(it);
//}
}

View File

@ -1,60 +1,144 @@
#ifndef __INCLUDED_DX12_HOOK_H__ /*
#define __INCLUDED_DX12_HOOK_H__ * Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "../Base_Hook.h" #pragma once
#ifdef EMU_OVERLAY
#include "../internal_includes.h"
#include <d3d12.h> #include <d3d12.h>
#include <dxgi1_4.h> #include <dxgi1_4.h>
#include "DirectX_VTables.h"
class DX12_Hook : public Base_Hook class DX12_Hook :
public Renderer_Hook,
public Base_Hook
{ {
public: public:
#define DX12_DLL "d3d12.dll" static constexpr const char *DLL_NAME = "d3d12.dll";
private: private:
static DX12_Hook* _inst; static DX12_Hook* _inst;
// Variables struct DX12Frame_t
bool hooked; {
bool initialized; D3D12_CPU_DESCRIPTOR_HANDLE RenderTarget = {};
ID3D12CommandAllocator* pCmdAlloc = nullptr;
ID3D12Resource* pBackBuffer = nullptr;
inline void Reset()
{
pCmdAlloc = nullptr;
pBackBuffer = nullptr;
}
DX12Frame_t(DX12Frame_t const&) = delete;
DX12Frame_t& operator=(DX12Frame_t const&) = delete;
DX12Frame_t(D3D12_CPU_DESCRIPTOR_HANDLE RenderTarget, ID3D12CommandAllocator* pCmdAlloc, ID3D12Resource* pBackBuffer):
RenderTarget(RenderTarget), pCmdAlloc(pCmdAlloc), pBackBuffer(pBackBuffer)
{}
DX12Frame_t(DX12Frame_t&& other) noexcept:
RenderTarget(other.RenderTarget), pCmdAlloc(other.pCmdAlloc), pBackBuffer(other.pBackBuffer)
{
other.Reset();
}
DX12Frame_t& operator=(DX12Frame_t&& other) noexcept
{
DX12Frame_t tmp(std::move(other));
RenderTarget = tmp.RenderTarget;
pCmdAlloc = tmp.pCmdAlloc;
pBackBuffer = tmp.pBackBuffer;
tmp.Reset();
return *this;
}
~DX12Frame_t()
{
if (pCmdAlloc != nullptr) pCmdAlloc->Release();
if (pBackBuffer != nullptr) pBackBuffer->Release();
}
};
// Variables
bool _Hooked;
bool _WindowsHooked;
bool _Initialized;
size_t CommandQueueOffset;
ID3D12CommandQueue* pCmdQueue; ID3D12CommandQueue* pCmdQueue;
UINT bufferCount; ID3D12Device* pDevice;
std::vector<D3D12_CPU_DESCRIPTOR_HANDLE> mainRenderTargets; std::vector<DX12Frame_t> OverlayFrames;
ID3D12CommandAllocator** pCmdAlloc; //std::vector<bool> srvDescHeapBitmap;
ID3D12DescriptorHeap* pSrvDescHeap; ID3D12DescriptorHeap* pSrvDescHeap;
ID3D12GraphicsCommandList* pCmdList; ID3D12GraphicsCommandList* pCmdList;
ID3D12DescriptorHeap* pRtvDescHeap; ID3D12DescriptorHeap* pRtvDescHeap;
ID3D12Resource** pBackBuffer;
// Functions // Functions
DX12_Hook(); DX12_Hook();
void resetRenderState(); //struct heap_t
void prepareForOverlay(IDXGISwapChain* pSwapChain); //{
// D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle;
// D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle;
// int64_t id;
//};
//
//heap_t get_free_texture_heap();
//bool release_texture_heap(int64_t heap_id);
ID3D12CommandQueue* _FindCommandQueueFromSwapChain(IDXGISwapChain* pSwapChain);
void _ResetRenderState();
void _PrepareForOverlay(IDXGISwapChain* pSwapChain, ID3D12CommandQueue* pCommandQueue);
// Hook to render functions // Hook to render functions
static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags); static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags);
static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters); static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters);
static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags); static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags);
static void STDMETHODCALLTYPE MyExecuteCommandLists(ID3D12CommandQueue *_this, UINT NumCommandLists, ID3D12CommandList* const* ppCommandLists); static void STDMETHODCALLTYPE MyExecuteCommandLists(ID3D12CommandQueue *_this, UINT NumCommandLists, ID3D12CommandList* const* ppCommandLists);
static HRESULT STDMETHODCALLTYPE MyPresent1(IDXGISwapChain1* _this, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters);
decltype(&IDXGISwapChain::Present) Present; decltype(&IDXGISwapChain::Present) Present;
decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers; decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers;
decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget; decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget;
decltype(&ID3D12CommandQueue::ExecuteCommandLists) ExecuteCommandLists; decltype(&ID3D12CommandQueue::ExecuteCommandLists) ExecuteCommandLists;
decltype(&IDXGISwapChain1::Present1) Present1;
public: public:
std::string LibraryName;
virtual ~DX12_Hook(); virtual ~DX12_Hook();
bool start_hook(); virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
virtual bool IsStarted();
static DX12_Hook* Inst(); static DX12_Hook* Inst();
virtual const char* get_lib_name() const; virtual std::string GetLibraryName() const;
void loadFunctions(ID3D12CommandQueue* pCommandQueue, IDXGISwapChain* pSwapChain); void LoadFunctions(
decltype(Present) PresentFcn,
decltype(ResizeBuffers) ResizeBuffersFcn,
decltype(ResizeTarget) ResizeTargetFcn,
decltype(ExecuteCommandLists) ExecuteCommandListsFcn,
decltype(Present1) Present1Fcn1);
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
}; };
#endif//EMU_OVERLAY
#endif//__INCLUDED_DX12_HOOK_H__

View File

@ -1,26 +1,58 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "DX9_Hook.h" #include "DX9_Hook.h"
#include "Windows_Hook.h" #include "Windows_Hook.h"
#include "../Renderer_Detector.h" #include "DirectX_VTables.h"
#include "../../dll/dll.h"
#ifdef EMU_OVERLAY
#include <imgui.h> #include <imgui.h>
#include <impls/windows/imgui_impl_dx9.h> #include <backends/imgui_impl_dx9.h>
DX9_Hook* DX9_Hook::_inst = nullptr; DX9_Hook* DX9_Hook::_inst = nullptr;
bool DX9_Hook::start_hook() template<typename T>
inline void SafeRelease(T*& pUnk)
{ {
if (!hooked) if (pUnk != nullptr)
{ {
if (!Windows_Hook::Inst()->start_hook()) pUnk->Release();
pUnk = nullptr;
}
}
bool DX9_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
{
if (!_Hooked)
{
if (Reset == nullptr || Present == nullptr)
{
SPDLOG_WARN("Failed to hook DirectX 9: Rendering functions missing.");
return false;
}
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
return false; return false;
PRINT_DEBUG("Hooked DirectX 9\n"); _WindowsHooked = true;
hooked = true;
SPDLOG_INFO("Hooked DirectX 9");
Renderer_Detector::Inst().renderer_found(this); _Hooked = true;
BeginHook(); BeginHook();
HookFuncs( HookFuncs(
@ -31,57 +63,89 @@ bool DX9_Hook::start_hook()
{ {
HookFuncs( HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)PresentEx, &DX9_Hook::MyPresentEx) std::make_pair<void**, void*>(&(PVOID&)PresentEx, &DX9_Hook::MyPresentEx)
//std::make_pair<void**, void*>(&(PVOID&)EndScene, &DX9_Hook::MyEndScene) );
}
if (SwapChainPresent != nullptr)
{
HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)SwapChainPresent, &DX9_Hook::MySwapChainPresent)
); );
} }
EndHook(); EndHook();
get_steam_client()->steam_overlay->HookReady();
} }
return true; return true;
} }
void DX9_Hook::resetRenderState() bool DX9_Hook::IsStarted()
{ {
if (initialized) return _Hooked;
}
void DX9_Hook::_ResetRenderState()
{
if (_Initialized)
{ {
initialized = false; OverlayHookReady(false);
ImGui_ImplDX9_Shutdown(); ImGui_ImplDX9_Shutdown();
Windows_Hook::Inst()->resetRenderState(); Windows_Hook::Inst()->_ResetRenderState();
ImGui::DestroyContext(); ImGui::DestroyContext();
SafeRelease(_pDevice);
_LastWindow = nullptr;
_Initialized = false;
} }
} }
// Try to make this function and overlay's proc as short as possible or it might affect game's fps. // Try to make this function and overlay's proc as short as possible or it might affect game's fps.
void DX9_Hook::prepareForOverlay(IDirect3DDevice9 *pDevice) void DX9_Hook::_PrepareForOverlay(IDirect3DDevice9 *pDevice, HWND destWindow)
{ {
D3DDEVICE_CREATION_PARAMETERS param; if (!destWindow)
pDevice->GetCreationParameters(&param); {
IDirect3DSwapChain9 *pSwapChain = nullptr;
if (pDevice->GetSwapChain(0, &pSwapChain) == D3D_OK)
{
D3DPRESENT_PARAMETERS params;
if (pSwapChain->GetPresentParameters(&params) == D3D_OK)
{
destWindow = params.hDeviceWindow;
}
pSwapChain->Release();
}
}
//Is this necessary anymore?
if (!destWindow)
{
D3DDEVICE_CREATION_PARAMETERS param;
pDevice->GetCreationParameters(&param);
destWindow = param.hFocusWindow;
}
// Workaround to detect if we changed window. // Workaround to detect if we changed window.
if (param.hFocusWindow != Windows_Hook::Inst()->GetGameHwnd()) if (destWindow != _LastWindow || _pDevice != pDevice)
resetRenderState(); _ResetRenderState();
if (!initialized) if (!_Initialized)
{ {
ImGui::CreateContext(); pDevice->AddRef();
ImGuiIO& io = ImGui::GetIO(); _pDevice = pDevice;
io.IniFilename = NULL;
ImGui::CreateContext();
ImGui_ImplDX9_Init(pDevice); ImGui_ImplDX9_Init(pDevice);
get_steam_client()->steam_overlay->CreateFonts(); _LastWindow = destWindow;
_Initialized = true;
initialized = true; OverlayHookReady(true);
} }
if (ImGui_ImplDX9_NewFrame())
{
Windows_Hook::Inst()->prepareForOverlay(param.hFocusWindow);
if (ImGui_ImplDX9_NewFrame() && Windows_Hook::Inst()->_PrepareForOverlay(destWindow))
{
ImGui::NewFrame(); ImGui::NewFrame();
get_steam_client()->steam_overlay->OverlayProc(); OverlayProc();
ImGui::Render(); ImGui::Render();
@ -91,55 +155,72 @@ void DX9_Hook::prepareForOverlay(IDirect3DDevice9 *pDevice)
HRESULT STDMETHODCALLTYPE DX9_Hook::MyReset(IDirect3DDevice9* _this, D3DPRESENT_PARAMETERS* pPresentationParameters) HRESULT STDMETHODCALLTYPE DX9_Hook::MyReset(IDirect3DDevice9* _this, D3DPRESENT_PARAMETERS* pPresentationParameters)
{ {
DX9_Hook::Inst()->resetRenderState(); auto inst = DX9_Hook::Inst();
return (_this->*DX9_Hook::Inst()->Reset)(pPresentationParameters); inst->_ResetRenderState();
} return (_this->*inst->Reset)(pPresentationParameters);
HRESULT STDMETHODCALLTYPE DX9_Hook::MyEndScene(IDirect3DDevice9* _this)
{
if( !DX9_Hook::Inst()->uses_present )
DX9_Hook::Inst()->prepareForOverlay(_this);
return (_this->*DX9_Hook::Inst()->EndScene)();
} }
HRESULT STDMETHODCALLTYPE DX9_Hook::MyPresent(IDirect3DDevice9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) HRESULT STDMETHODCALLTYPE DX9_Hook::MyPresent(IDirect3DDevice9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion)
{ {
DX9_Hook::Inst()->uses_present = true; auto inst = DX9_Hook::Inst();
DX9_Hook::Inst()->prepareForOverlay(_this); inst->_PrepareForOverlay(_this, hDestWindowOverride);
return (_this->*DX9_Hook::Inst()->Present)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion); return (_this->*inst->Present)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
} }
HRESULT STDMETHODCALLTYPE DX9_Hook::MyPresentEx(IDirect3DDevice9Ex* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags) HRESULT STDMETHODCALLTYPE DX9_Hook::MyPresentEx(IDirect3DDevice9Ex* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags)
{ {
DX9_Hook::Inst()->uses_present = true; auto inst = DX9_Hook::Inst();
DX9_Hook::Inst()->prepareForOverlay(_this); inst->_PrepareForOverlay(_this, hDestWindowOverride);
return (_this->*DX9_Hook::Inst()->PresentEx)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags); return (_this->*inst->PresentEx)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags);
}
HRESULT STDMETHODCALLTYPE DX9_Hook::MySwapChainPresent(IDirect3DSwapChain9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags)
{
IDirect3DDevice9* pDevice;
auto inst = DX9_Hook::Inst();
if (SUCCEEDED(_this->GetDevice(&pDevice)))
{
HWND destWindow = hDestWindowOverride;
if (!destWindow)
{
D3DPRESENT_PARAMETERS param;
if (_this->GetPresentParameters(&param) == D3D_OK)
{
destWindow = param.hDeviceWindow;
}
}
inst->_PrepareForOverlay(pDevice, destWindow);
pDevice->Release();
}
return (_this->*inst->SwapChainPresent)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags);
} }
DX9_Hook::DX9_Hook(): DX9_Hook::DX9_Hook():
initialized(false), _Initialized(false),
hooked(false), _Hooked(false),
uses_present(false), _WindowsHooked(false),
EndScene(nullptr), _LastWindow(nullptr),
Present(nullptr), Present(nullptr),
PresentEx(nullptr), PresentEx(nullptr),
Reset(nullptr) Reset(nullptr)
{ {
_library = LoadLibrary(DX9_DLL);
} }
DX9_Hook::~DX9_Hook() DX9_Hook::~DX9_Hook()
{ {
PRINT_DEBUG("DX9 Hook removed\n"); SPDLOG_INFO("DX9 Hook removed");
if (initialized) if (_WindowsHooked)
delete Windows_Hook::Inst();
if (_Initialized)
{ {
ImGui_ImplDX9_InvalidateDeviceObjects(); ImGui_ImplDX9_InvalidateDeviceObjects();
ImGui::DestroyContext(); ImGui::DestroyContext();
} }
FreeLibrary(reinterpret_cast<HMODULE>(_library));
_inst = nullptr; _inst = nullptr;
} }
@ -151,22 +232,94 @@ DX9_Hook* DX9_Hook::Inst()
return _inst; return _inst;
} }
const char* DX9_Hook::get_lib_name() const std::string DX9_Hook::GetLibraryName() const
{ {
return DX9_DLL; return LibraryName;
} }
void DX9_Hook::loadFunctions(IDirect3DDevice9* pDevice, bool ex) void DX9_Hook::LoadFunctions(decltype(Present) PresentFcn, decltype(Reset) ResetFcn, decltype(PresentEx) PresentExFcn, decltype(&IDirect3DSwapChain9::Present) SwapChainPresentFcn)
{ {
void** vTable = *reinterpret_cast<void***>(pDevice); Present = PresentFcn;
Reset = ResetFcn;
#define LOAD_FUNC(X) (void*&)X = vTable[(int)IDirect3DDevice9VTable::X] PresentEx = PresentExFcn;
LOAD_FUNC(Reset);
LOAD_FUNC(EndScene); SwapChainPresent = SwapChainPresentFcn;
LOAD_FUNC(Present);
if (ex)
LOAD_FUNC(PresentEx);
#undef LOAD_FUNC
} }
#endif//EMU_OVERLAY std::weak_ptr<uint64_t> DX9_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
{
IDirect3DTexture9** pTexture = new IDirect3DTexture9*(nullptr);
_pDevice->CreateTexture(
width,
height,
1,
D3DUSAGE_DYNAMIC,
D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT,
pTexture,
nullptr
);
if (*pTexture != nullptr)
{
D3DLOCKED_RECT rect;
if (SUCCEEDED((*pTexture)->LockRect(0, &rect, nullptr, D3DLOCK_DISCARD)))
{
const uint32_t* pixels = reinterpret_cast<const uint32_t*>(image_data);
uint8_t* texture_bits = reinterpret_cast<uint8_t*>(rect.pBits);
for (int32_t i = 0; i < height; ++i)
{
for (int32_t j = 0; j < width; ++j)
{
// RGBA to ARGB Conversion, DX9 doesn't have a RGBA loader
uint32_t color = *pixels++;
reinterpret_cast<uint32_t*>(texture_bits)[j] = ((color & 0xff) << 16) | (color & 0xff00) | ((color & 0xff0000) >> 16) | (color & 0xff000000);
}
texture_bits += rect.Pitch;
}
if (FAILED((*pTexture)->UnlockRect(0)))
{
(*pTexture)->Release();
delete pTexture;
pTexture = nullptr;
}
}
else
{
(*pTexture)->Release();
delete pTexture;
pTexture = nullptr;
}
}
if (pTexture == nullptr)
return std::shared_ptr<uint64_t>();
auto ptr = std::shared_ptr<uint64_t>((uint64_t*)pTexture, [](uint64_t* handle)
{
if (handle != nullptr)
{
IDirect3DTexture9** resource = reinterpret_cast<IDirect3DTexture9**>(handle);
(*resource)->Release();
delete resource;
}
});
_ImageResources.emplace(ptr);
return ptr;
}
void DX9_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
{
auto ptr = resource.lock();
if (ptr)
{
auto it = _ImageResources.find(ptr);
if (it != _ImageResources.end())
_ImageResources.erase(it);
}
}

View File

@ -1,52 +1,75 @@
#ifndef __INCLUDED_DX9_HOOK_H__ /*
#define __INCLUDED_DX9_HOOK_H__ * Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "../Base_Hook.h" #pragma once
#ifdef EMU_OVERLAY
#include "../internal_includes.h"
#include <d3d9.h> #include <d3d9.h>
#include "DirectX_VTables.h"
class DX9_Hook : public Base_Hook class DX9_Hook :
public Renderer_Hook,
public Base_Hook
{ {
public: public:
#define DX9_DLL "d3d9.dll" static constexpr const char *DLL_NAME = "d3d9.dll";
private: private:
static DX9_Hook* _inst; static DX9_Hook* _inst;
// Variables // Variables
bool hooked; bool _Hooked;
bool initialized; bool _WindowsHooked;
bool uses_present; bool _Initialized;
HWND _LastWindow;
IDirect3DDevice9* _pDevice;
std::set<std::shared_ptr<uint64_t>> _ImageResources;
// Functions // Functions
DX9_Hook(); DX9_Hook();
void resetRenderState(); void _ResetRenderState();
void prepareForOverlay(IDirect3DDevice9* pDevice); void _PrepareForOverlay(IDirect3DDevice9* pDevice, HWND destWindow);
// Hook to render functions // Hook to render functions
decltype(&IDirect3DDevice9::Reset) Reset; decltype(&IDirect3DDevice9::Reset) Reset;
decltype(&IDirect3DDevice9::EndScene) EndScene;
decltype(&IDirect3DDevice9::Present) Present; decltype(&IDirect3DDevice9::Present) Present;
decltype(&IDirect3DDevice9Ex::PresentEx) PresentEx; decltype(&IDirect3DDevice9Ex::PresentEx) PresentEx;
decltype(&IDirect3DSwapChain9::Present) SwapChainPresent;
static HRESULT STDMETHODCALLTYPE MyReset(IDirect3DDevice9* _this, D3DPRESENT_PARAMETERS* pPresentationParameters); static HRESULT STDMETHODCALLTYPE MyReset(IDirect3DDevice9* _this, D3DPRESENT_PARAMETERS* pPresentationParameters);
static HRESULT STDMETHODCALLTYPE MyEndScene(IDirect3DDevice9 *_this);
static HRESULT STDMETHODCALLTYPE MyPresent(IDirect3DDevice9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion); static HRESULT STDMETHODCALLTYPE MyPresent(IDirect3DDevice9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion);
static HRESULT STDMETHODCALLTYPE MyPresentEx(IDirect3DDevice9Ex* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags); static HRESULT STDMETHODCALLTYPE MyPresentEx(IDirect3DDevice9Ex* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags);
static HRESULT STDMETHODCALLTYPE MySwapChainPresent(IDirect3DSwapChain9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags);
public: public:
std::string LibraryName;
virtual ~DX9_Hook(); virtual ~DX9_Hook();
bool start_hook(); virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
virtual bool IsStarted();
static DX9_Hook* Inst(); static DX9_Hook* Inst();
virtual const char* get_lib_name() const; virtual std::string GetLibraryName() const;
void loadFunctions(IDirect3DDevice9 *pDevice, bool ex); void LoadFunctions(decltype(Present) PresentFcn, decltype(Reset) ResetFcn, decltype(PresentEx) PresentExFcn, decltype(&IDirect3DSwapChain9::Present) SwapChainPresentFcn);
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
}; };
#endif//EMU_OVERLAY
#endif//__INCLUDED_DX9_HOOK_H__

View File

@ -1,6 +1,23 @@
#pragma once /*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include <DXGI.h> #pragma once
enum class IDXGISwapChainVTable enum class IDXGISwapChainVTable
{ {
@ -446,3 +463,44 @@ enum class IDirect3DDevice9VTable
ResetEx, ResetEx,
GetDisplayModeEx, GetDisplayModeEx,
}; };
struct IDirect3DSwapChain9VTable
{
enum class Index
{
// IUnknown
QueryInterface,
AddRef,
Release,
// IDirect3DSwapChain9
Present,
GetFrontBufferData,
GetBackBuffer,
GetRasterStatus,
GetDisplayMode,
GetDevice,
GetPresentParameters,
// IDirect3DSwapChain9Ex
GetLastPresentCount,
GetPresentStats,
GetDisplayModeEx,
};
decltype(&IDirect3DSwapChain9::QueryInterface) pQueryInterface;
decltype(&IDirect3DSwapChain9::AddRef) pAddRef;
decltype(&IDirect3DSwapChain9::Release) pRelease;
decltype(&IDirect3DSwapChain9::Present) pPresent;
decltype(&IDirect3DSwapChain9::GetFrontBufferData) pGetFrontBufferData;
decltype(&IDirect3DSwapChain9::GetBackBuffer) pGetBackBuffer;
decltype(&IDirect3DSwapChain9::GetRasterStatus) pGetRasterStatus;
decltype(&IDirect3DSwapChain9::GetDisplayMode) pGetDisplayMode;
decltype(&IDirect3DSwapChain9::GetDevice) pGetDevice;
decltype(&IDirect3DSwapChain9::GetPresentParameters) pGetPresentParameters;
decltype(&IDirect3DSwapChain9Ex::GetLastPresentCount) pGetLastPresentCount;
decltype(&IDirect3DSwapChain9Ex::GetPresentStats) pGetPresentStats;
decltype(&IDirect3DSwapChain9Ex::GetDisplayModeEx) pGetDisplayModeEx;
};

View File

@ -1,96 +1,104 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "OpenGL_Hook.h" #include "OpenGL_Hook.h"
#include "Windows_Hook.h" #include "Windows_Hook.h"
#include "../Renderer_Detector.h"
#include "../../dll/dll.h"
#ifdef EMU_OVERLAY
#include <imgui.h> #include <imgui.h>
#include <impls/imgui_impl_opengl3.h> #include <backends/imgui_impl_opengl3.h>
#include <GL/glew.h> #include <glad/gl.h>
#include "../steam_overlay.h"
OpenGL_Hook* OpenGL_Hook::_inst = nullptr; OpenGL_Hook* OpenGL_Hook::_inst = nullptr;
bool OpenGL_Hook::start_hook() bool OpenGL_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
{ {
bool res = true; if (!_Hooked)
if (!hooked)
{ {
if (!Windows_Hook::Inst()->start_hook()) if (wglSwapBuffers == nullptr)
{
SPDLOG_WARN("Failed to hook OpenGL: Rendering functions missing.");
return false;
}
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
return false; return false;
GLenum err = glewInit(); _WindowsHooked = true;
if (err == GLEW_OK) SPDLOG_INFO("Hooked OpenGL");
{
PRINT_DEBUG("Hooked OpenGL\n");
hooked = true; _Hooked = true;
Renderer_Detector::Inst().renderer_found(this);
UnhookAll(); UnhookAll();
BeginHook(); BeginHook();
HookFuncs( HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)wglSwapBuffers, &OpenGL_Hook::MywglSwapBuffers) std::make_pair<void**, void*>(&(PVOID&)wglSwapBuffers, &OpenGL_Hook::MywglSwapBuffers)
); );
EndHook(); EndHook();
get_steam_client()->steam_overlay->HookReady();
}
else
{
PRINT_DEBUG("Failed to hook OpenGL\n");
/* Problem: glewInit failed, something is seriously wrong. */
PRINT_DEBUG("Error: %s\n", glewGetErrorString(err));
res = false;
}
} }
return true; return true;
} }
void OpenGL_Hook::resetRenderState() bool OpenGL_Hook::IsStarted()
{ {
if (initialized) return _Hooked;
}
void OpenGL_Hook::_ResetRenderState()
{
if (_Initialized)
{ {
OverlayHookReady(false);
ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplOpenGL3_Shutdown();
Windows_Hook::Inst()->resetRenderState(); Windows_Hook::Inst()->_ResetRenderState();
ImGui::DestroyContext(); ImGui::DestroyContext();
initialized = false; last_window = nullptr;
_Initialized = false;
} }
} }
// Try to make this function and overlay's proc as short as possible or it might affect game's fps. // Try to make this function and overlay's proc as short as possible or it might affect game's fps.
void OpenGL_Hook::prepareForOverlay(HDC hDC) void OpenGL_Hook::_PrepareForOverlay(HDC hDC)
{ {
HWND hWnd = WindowFromDC(hDC); HWND hWnd = WindowFromDC(hDC);
if (hWnd != Windows_Hook::Inst()->GetGameHwnd()) if (hWnd != last_window)
resetRenderState(); _ResetRenderState();
if (!initialized) if (!_Initialized)
{ {
ImGui::CreateContext(); ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.IniFilename = NULL;
ImGui_ImplOpenGL3_Init(); ImGui_ImplOpenGL3_Init();
get_steam_client()->steam_overlay->CreateFonts(); last_window = hWnd;
_Initialized = true;
initialized = true; OverlayHookReady(true);
} }
if (ImGui_ImplOpenGL3_NewFrame()) if (ImGui_ImplOpenGL3_NewFrame() && Windows_Hook::Inst()->_PrepareForOverlay(hWnd))
{ {
Windows_Hook::Inst()->prepareForOverlay(hWnd);
ImGui::NewFrame(); ImGui::NewFrame();
get_steam_client()->steam_overlay->OverlayProc(); OverlayProc();
ImGui::Render(); ImGui::Render();
@ -100,30 +108,33 @@ void OpenGL_Hook::prepareForOverlay(HDC hDC)
BOOL WINAPI OpenGL_Hook::MywglSwapBuffers(HDC hDC) BOOL WINAPI OpenGL_Hook::MywglSwapBuffers(HDC hDC)
{ {
OpenGL_Hook::Inst()->prepareForOverlay(hDC); auto inst = OpenGL_Hook::Inst();
return OpenGL_Hook::Inst()->wglSwapBuffers(hDC); inst->_PrepareForOverlay(hDC);
return inst->wglSwapBuffers(hDC);
} }
OpenGL_Hook::OpenGL_Hook(): OpenGL_Hook::OpenGL_Hook():
initialized(false), _Hooked(false),
hooked(false), _WindowsHooked(false),
_Initialized(false),
last_window(nullptr),
wglSwapBuffers(nullptr) wglSwapBuffers(nullptr)
{ {
_library = LoadLibrary(OPENGL_DLL);
} }
OpenGL_Hook::~OpenGL_Hook() OpenGL_Hook::~OpenGL_Hook()
{ {
PRINT_DEBUG("OpenGL Hook removed\n"); SPDLOG_INFO("OpenGL Hook removed");
if (initialized) if (_WindowsHooked)
delete Windows_Hook::Inst();
if (_Initialized)
{ {
ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplOpenGL3_Shutdown();
ImGui::DestroyContext(); ImGui::DestroyContext();
} }
FreeLibrary(reinterpret_cast<HMODULE>(_library));
_inst = nullptr; _inst = nullptr;
} }
@ -135,14 +146,62 @@ OpenGL_Hook* OpenGL_Hook::Inst()
return _inst; return _inst;
} }
const char* OpenGL_Hook::get_lib_name() const std::string OpenGL_Hook::GetLibraryName() const
{ {
return OPENGL_DLL; return LibraryName;
} }
void OpenGL_Hook::loadFunctions(wglSwapBuffers_t pfnwglSwapBuffers) void OpenGL_Hook::LoadFunctions(wglSwapBuffers_t pfnwglSwapBuffers)
{ {
wglSwapBuffers = pfnwglSwapBuffers; wglSwapBuffers = pfnwglSwapBuffers;
} }
#endif//EMU_OVERLAY std::weak_ptr<uint64_t> OpenGL_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
{
GLuint* texture = new GLuint(0);
glGenTextures(1, texture);
if (glGetError() != GL_NO_ERROR)
{
delete texture;
return std::shared_ptr<uint64_t>(nullptr);
}
// Save old texture id
GLint oldTex;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex);
glBindTexture(GL_TEXTURE_2D, *texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Upload pixels into texture
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
glBindTexture(GL_TEXTURE_2D, oldTex);
auto ptr = std::shared_ptr<uint64_t>((uint64_t*)texture, [](uint64_t* handle)
{
if (handle != nullptr)
{
GLuint* texture = (GLuint*)handle;
glDeleteTextures(1, texture);
delete texture;
}
});
_ImageResources.emplace(ptr);
return ptr;
}
void OpenGL_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
{
auto ptr = resource.lock();
if (ptr)
{
auto it = _ImageResources.find(ptr);
if (it != _ImageResources.end())
_ImageResources.erase(it);
}
}

View File

@ -1,13 +1,32 @@
#ifndef __INCLUDED_OPENGL_HOOK_H__ /*
#define __INCLUDED_OPENGL_HOOK_H__ * Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "../Base_Hook.h" #pragma once
#ifdef EMU_OVERLAY
class OpenGL_Hook : public Base_Hook #include "../internal_includes.h"
class OpenGL_Hook :
public Renderer_Hook,
public Base_Hook
{ {
public: public:
#define OPENGL_DLL "opengl32.dll" static constexpr const char *DLL_NAME = "opengl32.dll";
using wglSwapBuffers_t = BOOL(WINAPI*)(HDC); using wglSwapBuffers_t = BOOL(WINAPI*)(HDC);
@ -15,14 +34,17 @@ private:
static OpenGL_Hook* _inst; static OpenGL_Hook* _inst;
// Variables // Variables
bool hooked; bool _Hooked;
bool initialized; bool _WindowsHooked;
bool _Initialized;
HWND last_window;
std::set<std::shared_ptr<uint64_t>> _ImageResources;
// Functions // Functions
OpenGL_Hook(); OpenGL_Hook();
void resetRenderState(); void _ResetRenderState();
void prepareForOverlay(HDC hDC); void _PrepareForOverlay(HDC hDC);
// Hook to render functions // Hook to render functions
static BOOL WINAPI MywglSwapBuffers(HDC hDC); static BOOL WINAPI MywglSwapBuffers(HDC hDC);
@ -30,13 +52,16 @@ private:
wglSwapBuffers_t wglSwapBuffers; wglSwapBuffers_t wglSwapBuffers;
public: public:
std::string LibraryName;
virtual ~OpenGL_Hook(); virtual ~OpenGL_Hook();
bool start_hook(); virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
virtual bool IsStarted();
static OpenGL_Hook* Inst(); static OpenGL_Hook* Inst();
virtual const char* get_lib_name() const; virtual std::string GetLibraryName() const;
void loadFunctions(wglSwapBuffers_t pfnwglSwapBuffers); void LoadFunctions(wglSwapBuffers_t pfnwglSwapBuffers);
};
#endif//EMU_OVERLAY virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
#endif//__INCLUDED_OPENGL_HOOK_H__ virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
};

View File

@ -0,0 +1,128 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "Vulkan_Hook.h"
#include "Windows_Hook.h"
#include <imgui.h>
#include <backends/imgui_impl_vulkan.h>
Vulkan_Hook* Vulkan_Hook::_inst = nullptr;
bool Vulkan_Hook::StartHook(std::function<bool(bool)> key_combination_callback)
{
SPDLOG_WARN("Vulkan overlay is not yet supported.");
return false;
if (!_Hooked)
{
if (vkQueuePresentKHR == nullptr)
{
SPDLOG_WARN("Failed to hook Vulkan: Rendering functions missing.");
return false;
}
if (!Windows_Hook::Inst()->StartHook(key_combination_callback))
return false;
_WindowsHooked = true;
SPDLOG_INFO("Hooked Vulkan");
_Hooked = true;
BeginHook();
HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)vkQueuePresentKHR, &Vulkan_Hook::MyvkQueuePresentKHR)
);
EndHook();
}
return true;
}
bool Vulkan_Hook::IsStarted()
{
return _Hooked;
}
void Vulkan_Hook::_ResetRenderState()
{
}
// Try to make this function and overlay's proc as short as possible or it might affect game's fps.
void Vulkan_Hook::_PrepareForOverlay()
{
}
VKAPI_ATTR VkResult VKAPI_CALL Vulkan_Hook::MyvkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo)
{
auto inst = Vulkan_Hook::Inst();
inst->_PrepareForOverlay();
return inst->vkQueuePresentKHR(queue, pPresentInfo);
}
Vulkan_Hook::Vulkan_Hook():
_Hooked(false),
_WindowsHooked(false),
_Initialized(false),
vkQueuePresentKHR(nullptr)
{
}
Vulkan_Hook::~Vulkan_Hook()
{
SPDLOG_INFO("Vulkan_Hook Hook removed");
if (_WindowsHooked)
delete Windows_Hook::Inst();
if (_Initialized)
{
}
_inst = nullptr;
}
Vulkan_Hook* Vulkan_Hook::Inst()
{
if (_inst == nullptr)
_inst = new Vulkan_Hook;
return _inst;
}
std::string Vulkan_Hook::GetLibraryName() const
{
return LibraryName;
}
void Vulkan_Hook::LoadFunctions(decltype(::vkQueuePresentKHR)* _vkQueuePresentKHR)
{
vkQueuePresentKHR = _vkQueuePresentKHR;
}
std::weak_ptr<uint64_t> Vulkan_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
{
return std::shared_ptr<uint64_t>(nullptr);
}
void Vulkan_Hook::ReleaseImageResource(std::weak_ptr<uint64_t> resource)
{
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../internal_includes.h"
#include <vulkan/vulkan.h>
class Vulkan_Hook :
public Renderer_Hook,
public Base_Hook
{
public:
static constexpr const char *DLL_NAME = "vulkan-1.dll";
private:
static Vulkan_Hook* _inst;
// Variables
bool _Hooked;
bool _WindowsHooked;
bool _Initialized;
// Functions
Vulkan_Hook();
void _ResetRenderState();
void _PrepareForOverlay();
// Hook to render functions
static VKAPI_ATTR VkResult VKAPI_CALL MyvkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo);
decltype(::vkQueuePresentKHR)* vkQueuePresentKHR;
public:
std::string LibraryName;
virtual ~Vulkan_Hook();
virtual bool StartHook(std::function<bool(bool)> key_combination_callback);
virtual bool IsStarted();
static Vulkan_Hook* Inst();
virtual std::string GetLibraryName() const;
void LoadFunctions(decltype(::vkQueuePresentKHR)* _vkQueuePresentKHR);
virtual std::weak_ptr<uint64_t> CreateImageResource(const void* image_data, uint32_t width, uint32_t height);
virtual void ReleaseImageResource(std::weak_ptr<uint64_t> resource);
};

View File

@ -1,75 +1,152 @@
#include "Windows_Hook.h" /*
#include "../Renderer_Detector.h" * Copyright (C) Nemirtingas
#include "../../dll/dll.h" * This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#ifdef EMU_OVERLAY #include "Windows_Hook.h"
#include <imgui.h> #include <imgui.h>
#include <impls/windows/imgui_impl_win32.h> #include <backends/imgui_impl_win32.h>
#include <System/Library.h>
extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
constexpr decltype(Windows_Hook::DLL_NAME) Windows_Hook::DLL_NAME;
Windows_Hook* Windows_Hook::_inst = nullptr; Windows_Hook* Windows_Hook::_inst = nullptr;
bool Windows_Hook::start_hook() bool Windows_Hook::StartHook(std::function<bool(bool)>& _key_combination_callback)
{ {
bool res = true; if (!_Hooked)
if (!hooked)
{ {
GetRawInputBuffer = ::GetRawInputBuffer; void* hUser32 = System::Library::GetLibraryHandle(DLL_NAME);
GetRawInputData = ::GetRawInputData; if (hUser32 == nullptr)
SetCursorPos = ::SetCursorPos; {
SPDLOG_WARN("Failed to hook Windows: Cannot find {}", DLL_NAME);
return false;
}
PRINT_DEBUG("Hooked Windows\n"); System::Library::Library libUser32;
LibraryName = System::Library::GetLibraryPath(hUser32);
if (!libUser32.OpenLibrary(LibraryName, false))
{
SPDLOG_WARN("Failed to hook Windows: Cannot load {}", LibraryName);
return false;
}
GetRawInputBuffer = libUser32.GetSymbol<decltype(::GetRawInputBuffer)>("GetRawInputBuffer");
GetRawInputData = libUser32.GetSymbol<decltype(::GetRawInputData)>("GetRawInputData");
GetKeyState = libUser32.GetSymbol<decltype(::GetKeyState)>("GetKeyState");
GetAsyncKeyState = libUser32.GetSymbol<decltype(::GetAsyncKeyState)>("GetAsyncKeyState");
GetKeyboardState = libUser32.GetSymbol<decltype(::GetKeyboardState)>("GetKeyboardState");
GetCursorPos = libUser32.GetSymbol<decltype(::GetCursorPos)>("GetCursorPos");
SetCursorPos = libUser32.GetSymbol<decltype(::SetCursorPos)>("SetCursorPos");
if(GetRawInputBuffer == nullptr ||
GetRawInputData == nullptr ||
GetKeyState == nullptr ||
GetAsyncKeyState == nullptr ||
GetKeyboardState == nullptr ||
GetCursorPos == nullptr ||
SetCursorPos == nullptr)
{
SPDLOG_ERROR("Failed to hook Windows: Events functions missing.");
return false;
}
SPDLOG_INFO("Hooked Windows");
_KeyCombinationCallback = std::move(_key_combination_callback);
BeginHook(); BeginHook();
HookFuncs( HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)GetRawInputBuffer, &Windows_Hook::MyGetRawInputBuffer), std::make_pair<void**, void*>(&(PVOID&)GetRawInputBuffer, &Windows_Hook::MyGetRawInputBuffer),
std::make_pair<void**, void*>(&(PVOID&)GetRawInputData , &Windows_Hook::MyGetRawInputData), std::make_pair<void**, void*>(&(PVOID&)GetRawInputData , &Windows_Hook::MyGetRawInputData),
std::make_pair<void**, void*>(&(PVOID&)SetCursorPos , &Windows_Hook::MySetCursorPos) std::make_pair<void**, void*>(&(PVOID&)GetKeyState , &Windows_Hook::MyGetKeyState),
std::make_pair<void**, void*>(&(PVOID&)GetAsyncKeyState , &Windows_Hook::MyGetAsyncKeyState),
std::make_pair<void**, void*>(&(PVOID&)GetKeyboardState , &Windows_Hook::MyGetKeyboardState),
std::make_pair<void**, void*>(&(PVOID&)GetCursorPos , &Windows_Hook::MyGetCursorPos),
std::make_pair<void**, void*>(&(PVOID&)SetCursorPos , &Windows_Hook::MySetCursorPos)
); );
EndHook(); EndHook();
hooked = true; _Hooked = true;
} }
return res; return true;
} }
void Windows_Hook::resetRenderState() void Windows_Hook::_ResetRenderState()
{ {
if (initialized) if (_Initialized)
{ {
initialized = false; _Initialized = false;
SetWindowLongPtr(_game_hwnd, GWLP_WNDPROC, (LONG_PTR)_game_wndproc); SetWindowLongPtr(_GameHwnd, GWLP_WNDPROC, (LONG_PTR)_GameWndProc);
_game_hwnd = nullptr; _GameHwnd = nullptr;
_game_wndproc = nullptr; _GameWndProc = nullptr;
ImGui_ImplWin32_Shutdown(); ImGui_ImplWin32_Shutdown();
} }
} }
void Windows_Hook::prepareForOverlay(HWND hWnd) bool Windows_Hook::_PrepareForOverlay(HWND hWnd)
{ {
if (!initialized) if (_GameHwnd != hWnd)
_ResetRenderState();
if (!_Initialized)
{ {
ImGui_ImplWin32_Init(hWnd); _GameHwnd = hWnd;
ImGui_ImplWin32_Init(_GameHwnd);
_game_hwnd = hWnd; _GameWndProc = (WNDPROC)SetWindowLongPtr(_GameHwnd, GWLP_WNDPROC, (LONG_PTR)&Windows_Hook::HookWndProc);
_game_wndproc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)&Windows_Hook::HookWndProc); _Initialized = true;
initialized = true;
} }
ImGui_ImplWin32_NewFrame(); if (_Initialized)
{
void* current_proc = (void*)GetWindowLongPtr(_GameHwnd, GWLP_WNDPROC);
if (current_proc == nullptr)
return false;
ImGui_ImplWin32_NewFrame();
// Read keyboard modifiers inputs
auto& io = ImGui::GetIO();
POINT pos;
if (this->GetCursorPos(&pos) && ScreenToClient(hWnd, &pos))
{
io.MousePos = ImVec2((float)pos.x, (float)pos.y);
}
io.KeyCtrl = (this->GetKeyState(VK_CONTROL) & 0x8000) != 0;
io.KeyShift = (this->GetKeyState(VK_SHIFT) & 0x8000) != 0;
io.KeyAlt = (this->GetKeyState(VK_MENU) & 0x8000) != 0;
return true;
}
return false;
} }
HWND Windows_Hook::GetGameHwnd() const HWND Windows_Hook::GetGameHwnd() const
{ {
return _game_hwnd; return _GameHwnd;
} }
WNDPROC Windows_Hook::GetGameWndProc() const WNDPROC Windows_Hook::GetGameWndProc() const
{ {
return _game_wndproc; return _GameWndProc;
} }
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
@ -97,112 +174,207 @@ bool IgnoreMsg(UINT uMsg)
return false; return false;
} }
void RawMouseEvent(RAWINPUT& raw) void RawEvent(RAWINPUT& raw)
{ {
if (raw.header.dwType == RIM_TYPEMOUSE) HWND hWnd = Windows_Hook::Inst()->GetGameHwnd();
switch(raw.header.dwType)
{ {
if (raw.data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) case RIM_TYPEMOUSE:
ImGui_ImplWin32_WndProcHandler(Windows_Hook::Inst()->GetGameHwnd(), WM_LBUTTONDOWN, 0, 0); if (raw.data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN)
else if (raw.data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) ImGui_ImplWin32_WndProcHandler(hWnd, WM_LBUTTONDOWN, 0, 0);
ImGui_ImplWin32_WndProcHandler(Windows_Hook::Inst()->GetGameHwnd(), WM_LBUTTONUP, 0, 0); if (raw.data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP)
else if (raw.data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN) ImGui_ImplWin32_WndProcHandler(hWnd, WM_LBUTTONUP, 0, 0);
ImGui_ImplWin32_WndProcHandler(Windows_Hook::Inst()->GetGameHwnd(), WM_MBUTTONDOWN, 0, 0); if (raw.data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN)
else if (raw.data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP) ImGui_ImplWin32_WndProcHandler(hWnd, WM_RBUTTONDOWN, 0, 0);
ImGui_ImplWin32_WndProcHandler(Windows_Hook::Inst()->GetGameHwnd(), WM_MBUTTONUP, 0, 0); if (raw.data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP)
else if (raw.data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) ImGui_ImplWin32_WndProcHandler(hWnd, WM_RBUTTONUP, 0, 0);
ImGui_ImplWin32_WndProcHandler(Windows_Hook::Inst()->GetGameHwnd(), WM_RBUTTONDOWN, 0, 0); if (raw.data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN)
else if (raw.data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) ImGui_ImplWin32_WndProcHandler(hWnd, WM_MBUTTONDOWN, 0, 0);
ImGui_ImplWin32_WndProcHandler(Windows_Hook::Inst()->GetGameHwnd(), WM_RBUTTONUP, 0, 0); if (raw.data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP)
ImGui_ImplWin32_WndProcHandler(hWnd, WM_MBUTTONUP, 0, 0);
if (raw.data.mouse.usButtonFlags & RI_MOUSE_WHEEL)
ImGui_ImplWin32_WndProcHandler(hWnd, WM_MOUSEWHEEL, ((WPARAM)raw.data.mouse.usButtonData) << 16, 0);
if (raw.data.mouse.usButtonFlags & RI_MOUSE_HWHEEL)
ImGui_ImplWin32_WndProcHandler(hWnd, WM_MOUSEHWHEEL, ((WPARAM)raw.data.mouse.usButtonData) << 16, 0);
break;
//case RIM_TYPEKEYBOARD:
//ImGui_ImplWin32_WndProcHandler(hWnd, raw.data.keyboard.Message, raw.data.keyboard.VKey, 0);
//break;
} }
} }
LRESULT CALLBACK Windows_Hook::HookWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK Windows_Hook::HookWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ {
Steam_Overlay* overlay = get_steam_client()->steam_overlay; Windows_Hook* inst = Windows_Hook::Inst();
bool show = overlay->ShowOverlay(); bool skip_input = inst->_KeyCombinationCallback(false);
// Is the event is a key press bool clean_keys = false;
if (uMsg == WM_KEYDOWN) if (inst->_Initialized)
{ {
// Tab is pressed and was not pressed before // Is the event is a key press
if (wParam == VK_TAB && !(lParam & (1 << 30))) if (uMsg == WM_KEYDOWN)
{ {
// If Left Shift is pressed // Tab is pressed and was not pressed before
if (GetAsyncKeyState(VK_LSHIFT) & (1 << 15)) if (wParam == VK_TAB && !(lParam & (1 << 30)))
{ {
show = !overlay->ShowOverlay(); // If Left Shift is pressed
overlay->ShowOverlay(show); if (inst->GetAsyncKeyState(VK_LSHIFT) & (1 << 15))
{
if (inst->_KeyCombinationCallback(true))
{
skip_input = true;
// Save the last known cursor pos when opening the overlay
// so we can spoof the GetCursorPos return value.
inst->GetCursorPos(&inst->_SavedCursorPos);
}
else
{
clean_keys = true;
}
}
} }
} }
if (skip_input && IgnoreMsg(uMsg))
{
ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam);
if (clean_keys)
{
auto& io = ImGui::GetIO();
memset(io.KeysDown, 0, sizeof(io.KeysDown));
}
return 0;
}
} }
ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam); // Protect against recursive call of the WindowProc...
if (show) if (inst->_RecurseCallCount > 16)
{ return 0;
if (IgnoreMsg(uMsg))
return 0;
}
++inst->_RecurseCallCount;
// Call the overlay window procedure // Call the overlay window procedure
return CallWindowProc(Windows_Hook::Inst()->_game_wndproc, hWnd, uMsg, wParam, lParam); auto res = CallWindowProc(Windows_Hook::Inst()->_GameWndProc, hWnd, uMsg, wParam, lParam);
--inst->_RecurseCallCount;
return res;
} }
UINT WINAPI Windows_Hook::MyGetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader) UINT WINAPI Windows_Hook::MyGetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader)
{ {
if (pData == nullptr || !get_steam_client()->steam_overlay->ShowOverlay()) Windows_Hook* inst = Windows_Hook::Inst();
return Windows_Hook::Inst()->GetRawInputBuffer(pData, pcbSize, cbSizeHeader); int res = inst->GetRawInputBuffer(pData, pcbSize, cbSizeHeader);
if (!inst->_Initialized)
return res;
int num = Windows_Hook::Inst()->GetRawInputBuffer(pData, pcbSize, cbSizeHeader); if (pData != nullptr)
for (int i = 0; i < num; ++i) {
RawMouseEvent(pData[i]); for (int i = 0; i < res; ++i)
RawEvent(pData[i]);
}
if (!inst->_KeyCombinationCallback(false))
return res;
return 0; return 0;
} }
UINT WINAPI Windows_Hook::MyGetRawInputData(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader) UINT WINAPI Windows_Hook::MyGetRawInputData(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader)
{ {
if (pData == nullptr || !get_steam_client()->steam_overlay->ShowOverlay()) Windows_Hook* inst = Windows_Hook::Inst();
return Windows_Hook::Inst()->GetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader); auto res = inst->GetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader);
if (!inst->_Initialized || pData == nullptr)
return res;
Windows_Hook::Inst()->GetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader); if (uiCommand == RID_INPUT && res == sizeof(RAWINPUT))
RawEvent(*reinterpret_cast<RAWINPUT*>(pData));
RawMouseEvent(*reinterpret_cast<RAWINPUT*>(pData)); if (!inst->_KeyCombinationCallback(false))
return res;
memset(pData, 0, *pcbSize);
*pcbSize = 0; *pcbSize = 0;
return 0; return 0;
} }
BOOL WINAPI Windows_Hook::MySetCursorPos(int x, int y) SHORT WINAPI Windows_Hook::MyGetKeyState(int nVirtKey)
{ {
if (get_steam_client()->steam_overlay->ShowOverlay()) { Windows_Hook* inst = Windows_Hook::Inst();
POINT p;
GetCursorPos(&p); if (inst->_Initialized && inst->_KeyCombinationCallback(false))
x = p.x; return 0;
y = p.y;
return inst->GetKeyState(nVirtKey);
}
SHORT WINAPI Windows_Hook::MyGetAsyncKeyState(int vKey)
{
Windows_Hook* inst = Windows_Hook::Inst();
if (inst->_Initialized && inst->_KeyCombinationCallback(false))
return 0;
return inst->GetAsyncKeyState(vKey);
}
BOOL WINAPI Windows_Hook::MyGetKeyboardState(PBYTE lpKeyState)
{
Windows_Hook* inst = Windows_Hook::Inst();
if (inst->_Initialized && inst->_KeyCombinationCallback(false))
return FALSE;
return inst->GetKeyboardState(lpKeyState);
}
BOOL WINAPI Windows_Hook::MyGetCursorPos(LPPOINT lpPoint)
{
Windows_Hook* inst = Windows_Hook::Inst();
BOOL res = inst->GetCursorPos(lpPoint);
if (inst->_Initialized && inst->_KeyCombinationCallback(false) && lpPoint != nullptr)
{
*lpPoint = inst->_SavedCursorPos;
} }
return Windows_Hook::Inst()->SetCursorPos(x, y); return res;
} }
BOOL WINAPI Windows_Hook::MySetCursorPos(int X, int Y)
{
Windows_Hook* inst = Windows_Hook::Inst();
if (inst->_Initialized && inst->_KeyCombinationCallback(false))
{// That way, it will fail only if the real API fails.
// Hides error messages on some Unity debug builds.
POINT pos;
inst->GetCursorPos(&pos);
X = pos.x;
Y = pos.y;
}
return inst->SetCursorPos(X, Y);
}
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
Windows_Hook::Windows_Hook() : Windows_Hook::Windows_Hook() :
initialized(false), _Initialized(false),
hooked(false), _Hooked(false),
_game_hwnd(nullptr), _RecurseCallCount(0),
_game_wndproc(nullptr), _GameHwnd(nullptr),
_GameWndProc(nullptr),
GetRawInputBuffer(nullptr), GetRawInputBuffer(nullptr),
GetRawInputData(nullptr) GetRawInputData(nullptr),
GetKeyState(nullptr),
GetAsyncKeyState(nullptr),
GetKeyboardState(nullptr)
{ {
//_library = LoadLibrary(DLL_NAME);
} }
Windows_Hook::~Windows_Hook() Windows_Hook::~Windows_Hook()
{ {
PRINT_DEBUG("Windows Hook removed\n"); SPDLOG_INFO("Windows Hook removed");
resetRenderState(); _ResetRenderState();
//FreeLibrary(reinterpret_cast<HMODULE>(_library));
_inst = nullptr; _inst = nullptr;
} }
@ -215,9 +387,7 @@ Windows_Hook* Windows_Hook::Inst()
return _inst; return _inst;
} }
const char* Windows_Hook::get_lib_name() const std::string Windows_Hook::GetLibraryName() const
{ {
return WINDOWS_DLL; return LibraryName;
} }
#endif//EMU_OVERLAY

View File

@ -1,52 +1,80 @@
#ifndef __INCLUDED_WINDOWS_HOOK_H__ /*
#define __INCLUDED_WINDOWS_HOOK_H__ * Copyright (C) Nemirtingas
* This file is part of the ingame overlay project
*
* The ingame overlay project is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* The ingame overlay project is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the ingame overlay project; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "../Base_Hook.h" #pragma once
#ifdef __WINDOWS__ #include "../internal_includes.h"
#ifdef EMU_OVERLAY
class Windows_Hook : public Base_Hook class Windows_Hook :
public Base_Hook
{ {
public: public:
#define WINDOWS_DLL "user32.dll" static constexpr const char* DLL_NAME = "user32.dll";
private: private:
static Windows_Hook* _inst; static Windows_Hook* _inst;
// Variables // Variables
bool hooked; bool _Hooked;
bool initialized; bool _Initialized;
HWND _game_hwnd; int _RecurseCallCount;
WNDPROC _game_wndproc; HWND _GameHwnd;
WNDPROC _GameWndProc;
POINT _SavedCursorPos;
// Functions // Functions
Windows_Hook(); Windows_Hook();
// Hook to Windows window messages // Hook to Windows window messages
decltype(GetRawInputBuffer)* GetRawInputBuffer; decltype(::GetRawInputBuffer) *GetRawInputBuffer;
decltype(GetRawInputData)* GetRawInputData; decltype(::GetRawInputData) *GetRawInputData;
decltype(SetCursorPos)* SetCursorPos; decltype(::GetKeyState) *GetKeyState;
decltype(::GetAsyncKeyState) *GetAsyncKeyState;
decltype(::GetKeyboardState) *GetKeyboardState;
decltype(::GetCursorPos) *GetCursorPos;
decltype(::SetCursorPos) *SetCursorPos;
static LRESULT CALLBACK HookWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK HookWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static UINT WINAPI MyGetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader); static UINT WINAPI MyGetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader);
static UINT WINAPI MyGetRawInputData(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader); static UINT WINAPI MyGetRawInputData(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader);
static SHORT WINAPI MyGetKeyState(int nVirtKey);
static SHORT WINAPI MyGetAsyncKeyState(int vKey);
static BOOL WINAPI MyGetKeyboardState(PBYTE lpKeyState);
static BOOL WINAPI MyGetCursorPos(LPPOINT lpPoint);
static BOOL WINAPI MySetCursorPos(int X, int Y);
// In (bool): Is toggle wanted
// Out(bool): Is the overlay visible, if true, inputs will be disabled
std::function<bool(bool)> _KeyCombinationCallback;
static BOOL WINAPI MySetCursorPos(int x, int y);
public: public:
std::string LibraryName;
virtual ~Windows_Hook(); virtual ~Windows_Hook();
void resetRenderState(); void _ResetRenderState();
void prepareForOverlay(HWND); bool _PrepareForOverlay(HWND hWnd);
HWND GetGameHwnd() const; HWND GetGameHwnd() const;
WNDPROC GetGameWndProc() const; WNDPROC GetGameWndProc() const;
bool start_hook(); bool StartHook(std::function<bool(bool)>& key_combination_callback);
static Windows_Hook* Inst(); static Windows_Hook* Inst();
virtual const char* get_lib_name() const; virtual std::string GetLibraryName() const;
}; };
#endif//EMU_OVERLAY
#endif//__WINDOWS__
#endif//__INCLUDED_WINDOWS_HOOK_H__

File diff suppressed because it is too large Load Diff