├── Nox
├── d3d-api
│ └── ReadMe.me
├── libOpenGL
│ ├── ReagMe.md
│ ├── gl-zstencil.c
│ ├── gl-shaderparser.h
│ ├── gl-indexbuffer.c
│ ├── gl-texturecube.c
│ ├── gl-helpers.c
│ ├── gl-helpers.h
│ ├── gl-stagesurf.c
│ ├── gl-vertexbuffer.c
│ └── gl-texture2d.c
├── graphic-hook
│ ├── ReadMe.md
│ ├── dxgi-helpers.hpp
│ ├── d3d1x_shaders.hpp
│ ├── d3d9-patches.hpp
│ ├── graphics-hook.h
│ ├── gl-decs.h
│ ├── dxgi-capture.cpp
│ ├── d3d12-capture.cpp
│ └── d3d8-capture.cpp
├── Noxcap.def
├── ReadMe.md
├── stdafx.cpp
├── targetver.h
├── obfuscate.h
├── stdafx.h
├── obfuscate.c
├── funchook.h
├── hook-helpers.h
├── ReadMe.txt
├── graphics-hook-info.h
├── Noxcap.vcxproj.filters
├── Noxcap.h
├── funchook.c
└── Noxcap.vcxproj
├── NoxCap
├── Nox.h
├── Nox.aps
├── Nox.ico
├── Nox.rc
├── ReadMe.md
├── icon1.ico
├── small.ico
├── resource.h
├── Nox.vcxproj.user
├── RemoteOps.h
├── stdafx.cpp
├── targetver.h
├── obfuscate.h
├── app-helpers.h
├── stdafx.h
├── inject-library.h
├── obfuscate.c
├── Memory.h
├── hook-helpers.h
├── threading-posix.h
├── threading-windows.h
├── sched.c
├── bmem.h
├── app-helpers.c
├── semaphore.c
├── c99defs.h
├── ReadMe.txt
├── threading.h
├── Nox.vcxproj.filters
├── bmem.c
├── threading-windows.c
├── inject-library.c
├── semaphore.h
├── sched.h
├── threading-posix.c
├── nt-stuff.h
├── graphics-hook-info.h
└── gl-subsystem.h
├── s1.jpg
└── README.md
/Nox/d3d-api/ReadMe.me:
--------------------------------------------------------------------------------
1 | APIs for DirectX
2 |
--------------------------------------------------------------------------------
/Nox/libOpenGL/ReagMe.md:
--------------------------------------------------------------------------------
1 | Apis for OpenGL
2 |
--------------------------------------------------------------------------------
/Nox/graphic-hook/ReadMe.md:
--------------------------------------------------------------------------------
1 | Apis for hook
2 |
--------------------------------------------------------------------------------
/NoxCap/Nox.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "resource.h"
4 |
--------------------------------------------------------------------------------
/Nox/Noxcap.def:
--------------------------------------------------------------------------------
1 | LIBRARY NOXCAP
2 | EXPORTS
3 | hook_swap_buffers @1
4 |
--------------------------------------------------------------------------------
/s1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Gbapy/NoxPlayer-Recorder-by-hooking-the-DirectX-OpenGL/HEAD/s1.jpg
--------------------------------------------------------------------------------
/NoxCap/Nox.aps:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Gbapy/NoxPlayer-Recorder-by-hooking-the-DirectX-OpenGL/HEAD/NoxCap/Nox.aps
--------------------------------------------------------------------------------
/NoxCap/Nox.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Gbapy/NoxPlayer-Recorder-by-hooking-the-DirectX-OpenGL/HEAD/NoxCap/Nox.ico
--------------------------------------------------------------------------------
/NoxCap/Nox.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Gbapy/NoxPlayer-Recorder-by-hooking-the-DirectX-OpenGL/HEAD/NoxCap/Nox.rc
--------------------------------------------------------------------------------
/NoxCap/ReadMe.md:
--------------------------------------------------------------------------------
1 | This is the source code that hooks the DirectX/OpenGL to capture the buffer shown in the NoxPlayer
2 |
--------------------------------------------------------------------------------
/NoxCap/icon1.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Gbapy/NoxPlayer-Recorder-by-hooking-the-DirectX-OpenGL/HEAD/NoxCap/icon1.ico
--------------------------------------------------------------------------------
/NoxCap/small.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Gbapy/NoxPlayer-Recorder-by-hooking-the-DirectX-OpenGL/HEAD/NoxCap/small.ico
--------------------------------------------------------------------------------
/NoxCap/resource.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Gbapy/NoxPlayer-Recorder-by-hooking-the-DirectX-OpenGL/HEAD/NoxCap/resource.h
--------------------------------------------------------------------------------
/Nox/ReadMe.md:
--------------------------------------------------------------------------------
1 | This is the source code to communicate with NoxCap and get result from hooked buffer and show it on the screen.
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NoxPlayer-Recorder
2 | This project captures the screen of the NoxPlayer that is using DirectX/OpenGL for representation of its screen.
3 | 
4 |
--------------------------------------------------------------------------------
/NoxCap/Nox.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Nox/stdafx.cpp:
--------------------------------------------------------------------------------
1 | // stdafx.cpp : source file that includes just the standard includes
2 | // Noxcap.pch will be the pre-compiled header
3 | // stdafx.obj will contain the pre-compiled type information
4 |
5 | #include "stdafx.h"
6 |
7 | // TODO: reference any additional headers you need in STDAFX.H
8 | // and not in this file
9 |
--------------------------------------------------------------------------------
/NoxCap/RemoteOps.h:
--------------------------------------------------------------------------------
1 | /* RemoteOps.h */
2 |
3 | #ifndef REM_OPS_H
4 | #define REM_OPS_H
5 |
6 | HMODULE WINAPI GetRemoteModuleHandle(HANDLE hProcess, LPCSTR lpModuleName);
7 | FARPROC WINAPI GetRemoteProcAddress(HANDLE hProcess, HMODULE hModule, LPCSTR lpProcName, UINT Ordinal = 0, BOOL UseOrdinal = FALSE);
8 |
9 | #endif //REM_OPS_H
--------------------------------------------------------------------------------
/NoxCap/stdafx.cpp:
--------------------------------------------------------------------------------
1 | // stdafx.cpp : source file that includes just the standard includes
2 | // Nox.pch will be the pre-compiled header
3 | // stdafx.obj will contain the pre-compiled type information
4 |
5 | #include "stdafx.h"
6 |
7 | // TODO: reference any additional headers you need in STDAFX.H
8 | // and not in this file
9 |
--------------------------------------------------------------------------------
/Nox/targetver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Including SDKDDKVer.h defines the highest available Windows platform.
4 |
5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
7 |
8 | #include
9 |
--------------------------------------------------------------------------------
/NoxCap/targetver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Including SDKDDKVer.h defines the highest available Windows platform.
4 |
5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
7 |
8 | #include
9 |
--------------------------------------------------------------------------------
/Nox/graphic-hook/dxgi-helpers.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | static inline DXGI_FORMAT fix_dxgi_format(DXGI_FORMAT format)
4 | {
5 | switch ((unsigned long)format) {
6 | case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
7 | return DXGI_FORMAT_B8G8R8A8_UNORM;
8 | case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
9 | return DXGI_FORMAT_R8G8B8A8_UNORM;
10 | }
11 |
12 | return format;
13 | }
14 |
--------------------------------------------------------------------------------
/Nox/obfuscate.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #ifdef __cplusplus
6 | extern "C" {
7 | #endif
8 |
9 | /* this is a workaround to A/Vs going crazy whenever certain functions (such as
10 | * OpenProcess) are used */
11 | extern void *get_obfuscated_func(HMODULE module, const char *str, uint64_t val);
12 |
13 | #ifdef __cplusplus
14 | }
15 | #endif
16 |
--------------------------------------------------------------------------------
/NoxCap/obfuscate.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #ifdef __cplusplus
6 | extern "C" {
7 | #endif
8 |
9 | /* this is a workaround to A/Vs going crazy whenever certain functions (such as
10 | * OpenProcess) are used */
11 | extern void *get_obfuscated_func(HMODULE module, const char *str, uint64_t val);
12 |
13 | #ifdef __cplusplus
14 | }
15 | #endif
16 |
--------------------------------------------------------------------------------
/NoxCap/app-helpers.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "stdafx.h"
3 | #include
4 |
5 | #ifdef __cplusplus
6 | extern "C" {
7 | #endif
8 | extern bool is_app(HANDLE process);
9 | extern wchar_t *get_app_sid(HANDLE process);
10 | extern HANDLE open_app_mutex(const wchar_t *sid, const wchar_t *name);
11 | extern HANDLE open_app_event(const wchar_t *sid, const wchar_t *name);
12 | extern HANDLE open_app_map(const wchar_t *sid, const wchar_t *name);
13 | #ifdef __cplusplus
14 | }
15 | #endif
--------------------------------------------------------------------------------
/Nox/stdafx.h:
--------------------------------------------------------------------------------
1 | // stdafx.h : include file for standard system include files,
2 | // or project specific include files that are used frequently, but
3 | // are changed infrequently
4 | //
5 |
6 | #pragma once
7 |
8 | #include "targetver.h"
9 |
10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
11 | // Windows Header Files:
12 | #include
13 |
14 |
15 |
16 | // TODO: reference additional headers your program requires here
17 |
--------------------------------------------------------------------------------
/NoxCap/stdafx.h:
--------------------------------------------------------------------------------
1 | // stdafx.h : include file for standard system include files,
2 | // or project specific include files that are used frequently, but
3 | // are changed infrequently
4 | //
5 |
6 | #pragma once
7 |
8 | #include "targetver.h"
9 |
10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
11 | // Windows Header Files:
12 | #include
13 |
14 | // C RunTime Header Files
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 |
21 | // TODO: reference additional headers your program requires here
22 |
--------------------------------------------------------------------------------
/Nox/graphic-hook/d3d1x_shaders.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | static const char vertex_shader_string[] = "struct VertData \
4 | { \
5 | float4 pos : SV_Position; \
6 | float2 texCoord : TexCoord0; \
7 | }; \
8 | VertData main(VertData input) \
9 | { \
10 | VertData output; \
11 | output.pos = input.pos; \
12 | output.texCoord = input.texCoord; \
13 | return output; \
14 | }";
15 |
16 | static const char pixel_shader_string[] = "uniform Texture2D diffuseTexture; \
17 | SamplerState textureSampler \
18 | { \
19 | AddressU = Clamp; \
20 | AddressV = Clamp; \
21 | Filter = Linear; \
22 | }; \
23 | struct VertData \
24 | { \
25 | float4 pos : SV_Position; \
26 | float2 texCoord : TexCoord0; \
27 | }; \
28 | float4 main(VertData input) : SV_Target \
29 | { \
30 | return diffuseTexture.Sample(textureSampler, input.texCoord); \
31 | }";
32 |
--------------------------------------------------------------------------------
/NoxCap/inject-library.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 |
5 |
6 | #define INJECT_ERROR_INJECT_FAILED -1
7 | #define INJECT_ERROR_INVALID_PARAMS -2
8 | #define INJECT_ERROR_OPEN_PROCESS_FAIL -3
9 | #define INJECT_ERROR_UNLIKELY_FAIL -4
10 |
11 | #ifdef __cplusplus
12 | extern "C" {
13 | #endif
14 | extern int inject_library_obf(HANDLE process, const wchar_t *dll,
15 | const char *create_remote_thread_obf,
16 | uint64_t obf1,
17 | const char *write_process_memory_obf,
18 | uint64_t obf2, const char *virtual_alloc_ex_obf,
19 | uint64_t obf3, const char *virtual_free_ex_obf,
20 | uint64_t obf4, const char *load_library_w_obf,
21 | uint64_t obf5);
22 |
23 | extern int inject_library_safe_obf(DWORD thread_id, const wchar_t *dll,
24 | const char *set_windows_hook_ex_obf,
25 | uint64_t obf1);
26 | #ifdef __cplusplus
27 | }
28 | #endif
--------------------------------------------------------------------------------
/Nox/obfuscate.c:
--------------------------------------------------------------------------------
1 | #ifdef _MSC_VER
2 | #pragma warning(disable : 4152) /* casting func ptr to void */
3 | #endif
4 |
5 | #include
6 | #include
7 | #include "obfuscate.h"
8 |
9 | #define LOWER_HALFBYTE(x) ((x)&0xF)
10 | #define UPPER_HALFBYTE(x) (((x) >> 4) & 0xF)
11 |
12 | static void deobfuscate_str(char *str, uint64_t val)
13 | {
14 | uint8_t *dec_val = (uint8_t *)&val;
15 | int i = 0;
16 |
17 | while (*str != 0) {
18 | int pos = i / 2;
19 | bool bottom = (i % 2) == 0;
20 | uint8_t *ch = (uint8_t *)str;
21 | uint8_t xor = bottom ? LOWER_HALFBYTE(dec_val[pos])
22 | : UPPER_HALFBYTE(dec_val[pos]);
23 |
24 | *ch ^= xor;
25 |
26 | if (++i == sizeof(uint64_t) * 2)
27 | i = 0;
28 |
29 | str++;
30 | }
31 | }
32 |
33 | void *get_obfuscated_func(HMODULE module, const char *str, uint64_t val)
34 | {
35 | char new_name[128];
36 | strcpy(new_name, str);
37 | deobfuscate_str(new_name, val);
38 | return GetProcAddress(module, new_name);
39 | }
40 |
--------------------------------------------------------------------------------
/NoxCap/obfuscate.c:
--------------------------------------------------------------------------------
1 | #ifdef _MSC_VER
2 | #pragma warning(disable : 4152) /* casting func ptr to void */
3 | #endif
4 |
5 | #include
6 | #include
7 | #include "obfuscate.h"
8 |
9 | #define LOWER_HALFBYTE(x) ((x)&0xF)
10 | #define UPPER_HALFBYTE(x) (((x) >> 4) & 0xF)
11 |
12 | static void deobfuscate_str(char *str, uint64_t val)
13 | {
14 | uint8_t *dec_val = (uint8_t *)&val;
15 | int i = 0;
16 |
17 | while (*str != 0) {
18 | int pos = i / 2;
19 | bool bottom = (i % 2) == 0;
20 | uint8_t *ch = (uint8_t *)str;
21 | uint8_t xor = bottom ? LOWER_HALFBYTE(dec_val[pos])
22 | : UPPER_HALFBYTE(dec_val[pos]);
23 |
24 | *ch ^= xor;
25 |
26 | if (++i == sizeof(uint64_t) * 2)
27 | i = 0;
28 |
29 | str++;
30 | }
31 | }
32 |
33 | void *get_obfuscated_func(HMODULE module, const char *str, uint64_t val)
34 | {
35 | char new_name[128];
36 | strcpy(new_name, str);
37 | deobfuscate_str(new_name, val);
38 | return GetProcAddress(module, new_name);
39 | }
40 |
--------------------------------------------------------------------------------
/NoxCap/Memory.h:
--------------------------------------------------------------------------------
1 | #include
2 | namespace Memory
3 | {
4 | template
5 | T Read(DWORD address)
6 | {
7 | return *((T*)address);
8 | }
9 |
10 | template
11 | void Write(DWORD address, T value)
12 | {
13 | *((T*)address) = value;
14 | }
15 |
16 | template
17 | DWORD Protect(DWORD address, DWORD prot)
18 | {
19 | DWORD oldProt;
20 | VirtualProtect((LPVOID)address, sizeof(T), prot, &oldProt);
21 | return oldProt;
22 | }
23 | DWORD JumpHook(DWORD hookAt, DWORD newFunc, int size)
24 | {
25 | DWORD newOffset = newFunc - hookAt - 5; // -5 cuz its relative to the next instruction
26 | auto oldProtection = Memory::Protect(hookAt + 1, PAGE_EXECUTE_READWRITE);
27 | Memory::Write(hookAt, 0xE9); //JMP
28 | Memory::Write(hookAt + 1, newOffset);
29 | for (unsigned int i = 5; i < size; i++) //NOP extra bytes so it doesnt corrupt any instructions
30 | Memory::Write(hookAt + i, 0x90);
31 | Memory::Protect(hookAt + 1, oldProtection);
32 | return hookAt + 5;
33 | }
34 | }
--------------------------------------------------------------------------------
/Nox/funchook.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | #ifdef __cplusplus
7 | extern "C" {
8 | #else
9 | #if defined(_MSC_VER) && !defined(inline)
10 | #define inline __inline
11 | #endif
12 | #endif
13 |
14 | enum hook_type {
15 | HOOKTYPE_FORWARD_OVERWRITE,
16 | HOOKTYPE_FORWARD_CHAIN,
17 | HOOKTYPE_REVERSE_CHAIN
18 | };
19 |
20 | struct func_hook {
21 | void *call_addr;
22 |
23 | uintptr_t func_addr; /* function being hooked to */
24 | uintptr_t hook_addr; /* hook function itself */
25 | void *bounce_addr;
26 | const char *name;
27 | enum hook_type type;
28 | bool is_64bit_jump;
29 | bool hooked;
30 | bool started;
31 | bool attempted_bounce;
32 | uint8_t unhook_data[14];
33 | uint8_t rehook_data[14];
34 | };
35 |
36 | extern void hook_init(struct func_hook *hook, void *func_addr, void *hook_addr,
37 | const char *name);
38 | extern void hook_start(struct func_hook *hook);
39 | extern void do_hook(struct func_hook *hook, bool force);
40 | extern void unhook(struct func_hook *hook);
41 |
42 | static inline void rehook(struct func_hook *hook)
43 | {
44 | do_hook(hook, false);
45 | }
46 |
47 | static inline void force_rehook(struct func_hook *hook)
48 | {
49 | do_hook(hook, true);
50 | }
51 |
52 | #ifdef __cplusplus
53 | }
54 | #endif
55 |
--------------------------------------------------------------------------------
/Nox/hook-helpers.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #if !defined(__cplusplus) && !defined(inline)
4 | #define inline __inline
5 | #endif
6 |
7 | #define GC_EVENT_FLAGS (EVENT_MODIFY_STATE | SYNCHRONIZE)
8 | #define GC_MUTEX_FLAGS (SYNCHRONIZE)
9 |
10 | static inline HANDLE create_event(const wchar_t *name)
11 | {
12 | return CreateEventW(NULL, false, false, name);
13 | }
14 |
15 | static inline HANDLE open_event(const wchar_t *name)
16 | {
17 | return OpenEventW(GC_EVENT_FLAGS, false, name);
18 | }
19 |
20 | static inline HANDLE create_mutex(const wchar_t *name)
21 | {
22 | return CreateMutexW(NULL, false, name);
23 | }
24 |
25 | static inline HANDLE open_mutex(const wchar_t *name)
26 | {
27 | return OpenMutexW(GC_MUTEX_FLAGS, false, name);
28 | }
29 |
30 | static inline HANDLE create_event_plus_id(const wchar_t *name, DWORD id)
31 | {
32 | wchar_t new_name[64];
33 | _snwprintf(new_name, 64, L"%s%lu", name, id);
34 | return create_event(new_name);
35 | }
36 |
37 | static inline HANDLE create_mutex_plus_id(const wchar_t *name, DWORD id)
38 | {
39 | wchar_t new_name[64];
40 | _snwprintf(new_name, 64, L"%s%lu", name, id);
41 | return create_mutex(new_name);
42 | }
43 |
44 | static inline bool object_signalled(HANDLE event)
45 | {
46 | if (!event)
47 | return false;
48 |
49 | return WaitForSingleObject(event, 0) == WAIT_OBJECT_0;
50 | }
51 |
--------------------------------------------------------------------------------
/NoxCap/hook-helpers.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | #if !defined(__cplusplus) && !defined(inline)
5 | #define inline __inline
6 | #endif
7 |
8 | #define GC_EVENT_FLAGS (EVENT_MODIFY_STATE | SYNCHRONIZE)
9 | #define GC_MUTEX_FLAGS (SYNCHRONIZE)
10 |
11 | static inline HANDLE create_event(const wchar_t *name)
12 | {
13 | return CreateEventW(NULL, false, false, name);
14 | }
15 |
16 | static inline HANDLE open_event(const wchar_t *name)
17 | {
18 | return OpenEventW(GC_EVENT_FLAGS, false, name);
19 | }
20 |
21 | static inline HANDLE create_mutex(const wchar_t *name)
22 | {
23 | return CreateMutexW(NULL, false, name);
24 | }
25 |
26 | static inline HANDLE open_mutex(const wchar_t *name)
27 | {
28 | return OpenMutexW(GC_MUTEX_FLAGS, false, name);
29 | }
30 |
31 | static inline HANDLE create_event_plus_id(const wchar_t *name, DWORD id)
32 | {
33 | wchar_t new_name[64];
34 | _snwprintf(new_name, 64, L"%s%lu", name, id);
35 | return create_event(new_name);
36 | }
37 |
38 | static inline HANDLE create_mutex_plus_id(const wchar_t *name, DWORD id)
39 | {
40 | wchar_t new_name[64];
41 | _snwprintf(new_name, 64, L"%s%lu", name, id);
42 | return create_mutex(new_name);
43 | }
44 |
45 | static inline bool object_signalled(HANDLE event)
46 | {
47 | if (!event)
48 | return false;
49 |
50 | return WaitForSingleObject(event, 0) == WAIT_OBJECT_0;
51 | }
52 |
--------------------------------------------------------------------------------
/NoxCap/threading-posix.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 Hugh Bailey
3 | *
4 | * Permission to use, copy, modify, and distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 |
17 | #pragma once
18 |
19 | static inline long os_atomic_inc_long(volatile long *val)
20 | {
21 | return __sync_add_and_fetch(val, 1);
22 | }
23 |
24 | static inline long os_atomic_dec_long(volatile long *val)
25 | {
26 | return __sync_sub_and_fetch(val, 1);
27 | }
28 |
29 | static inline long os_atomic_set_long(volatile long *ptr, long val)
30 | {
31 | return __sync_lock_test_and_set(ptr, val);
32 | }
33 |
34 | static inline long os_atomic_load_long(const volatile long *ptr)
35 | {
36 | return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
37 | }
38 |
39 | static inline bool os_atomic_compare_swap_long(volatile long *val, long old_val,
40 | long new_val)
41 | {
42 | return __sync_bool_compare_and_swap(val, old_val, new_val);
43 | }
44 |
45 | static inline bool os_atomic_set_bool(volatile bool *ptr, bool val)
46 | {
47 | return __sync_lock_test_and_set(ptr, val);
48 | }
49 |
50 | static inline bool os_atomic_load_bool(const volatile bool *ptr)
51 | {
52 | return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
53 | }
54 |
--------------------------------------------------------------------------------
/NoxCap/threading-windows.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 Hugh Bailey
3 | *
4 | * Permission to use, copy, modify, and distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 |
17 | #pragma once
18 |
19 | #include
20 |
21 | static inline long os_atomic_inc_long(volatile long *val)
22 | {
23 | return _InterlockedIncrement(val);
24 | }
25 |
26 | static inline long os_atomic_dec_long(volatile long *val)
27 | {
28 | return _InterlockedDecrement(val);
29 | }
30 |
31 | static inline long os_atomic_set_long(volatile long *ptr, long val)
32 | {
33 | return (long)_InterlockedExchange((volatile long *)ptr, (long)val);
34 | }
35 |
36 | static inline long os_atomic_load_long(const volatile long *ptr)
37 | {
38 | return (long)_InterlockedOr((volatile long *)ptr, 0);
39 | }
40 |
41 | static inline bool os_atomic_compare_swap_long(volatile long *val, long old_val,
42 | long new_val)
43 | {
44 | return _InterlockedCompareExchange(val, new_val, old_val) == old_val;
45 | }
46 |
47 | static inline bool os_atomic_set_bool(volatile bool *ptr, bool val)
48 | {
49 | return !!_InterlockedExchange8((volatile char *)ptr, (char)val);
50 | }
51 |
52 | static inline bool os_atomic_load_bool(const volatile bool *ptr)
53 | {
54 | return !!_InterlockedOr8((volatile char *)ptr, 0);
55 | }
56 |
--------------------------------------------------------------------------------
/NoxCap/sched.c:
--------------------------------------------------------------------------------
1 | /*
2 | * sched.c
3 | *
4 | * Description:
5 | * POSIX thread functions that deal with thread scheduling.
6 | *
7 | * --------------------------------------------------------------------------
8 | *
9 | * Pthreads-win32 - POSIX Threads Library for Win32
10 | * Copyright(C) 1998 John E. Bossom
11 | * Copyright(C) 1999,2005 Pthreads-win32 contributors
12 | *
13 | * Contact Email: rpj@callisto.canberra.edu.au
14 | *
15 | * The current list of contributors is contained
16 | * in the file CONTRIBUTORS included with the source
17 | * code distribution. The list can also be seen at the
18 | * following World Wide Web location:
19 | * http://sources.redhat.com/pthreads-win32/contributors.html
20 | *
21 | * This library is free software; you can redistribute it and/or
22 | * modify it under the terms of the GNU Lesser General Public
23 | * License as published by the Free Software Foundation; either
24 | * version 2 of the License, or (at your option) any later version.
25 | *
26 | * This library is distributed in the hope that it will be useful,
27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29 | * Lesser General Public License for more details.
30 | *
31 | * You should have received a copy of the GNU Lesser General Public
32 | * License along with this library in the file COPYING.LIB;
33 | * if not, write to the Free Software Foundation, Inc.,
34 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
35 | */
36 |
37 | #include "pthread.h"
38 | #include "implement.h"
39 | #include "sched.h"
40 |
41 | #include "pthread_attr_setschedpolicy.c"
42 | #include "pthread_attr_getschedpolicy.c"
43 | #include "pthread_attr_setschedparam.c"
44 | #include "pthread_attr_getschedparam.c"
45 | #include "pthread_attr_setinheritsched.c"
46 | #include "pthread_attr_getinheritsched.c"
47 | #include "pthread_setschedparam.c"
48 | #include "pthread_getschedparam.c"
49 | #include "sched_get_priority_max.c"
50 | #include "sched_get_priority_min.c"
51 | #include "sched_setscheduler.c"
52 | #include "sched_getscheduler.c"
53 | #include "sched_yield.c"
54 |
--------------------------------------------------------------------------------
/Nox/ReadMe.txt:
--------------------------------------------------------------------------------
1 | ========================================================================
2 | DYNAMIC LINK LIBRARY : Noxcap Project Overview
3 | ========================================================================
4 |
5 | AppWizard has created this Noxcap DLL for you.
6 |
7 | This file contains a summary of what you will find in each of the files that
8 | make up your Noxcap application.
9 |
10 |
11 | Noxcap.vcxproj
12 | This is the main project file for VC++ projects generated using an Application Wizard.
13 | It contains information about the version of Visual C++ that generated the file, and
14 | information about the platforms, configurations, and project features selected with the
15 | Application Wizard.
16 |
17 | Noxcap.vcxproj.filters
18 | This is the filters file for VC++ projects generated using an Application Wizard.
19 | It contains information about the association between the files in your project
20 | and the filters. This association is used in the IDE to show grouping of files with
21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the
22 | "Source Files" filter).
23 |
24 | Noxcap.cpp
25 | This is the main DLL source file.
26 |
27 | When created, this DLL does not export any symbols. As a result, it
28 | will not produce a .lib file when it is built. If you wish this project
29 | to be a project dependency of some other project, you will either need to
30 | add code to export some symbols from the DLL so that an export library
31 | will be produced, or you can set the Ignore Input Library property to Yes
32 | on the General propert page of the Linker folder in the project's Property
33 | Pages dialog box.
34 |
35 | /////////////////////////////////////////////////////////////////////////////
36 | Other standard files:
37 |
38 | StdAfx.h, StdAfx.cpp
39 | These files are used to build a precompiled header (PCH) file
40 | named Noxcap.pch and a precompiled types file named StdAfx.obj.
41 |
42 | /////////////////////////////////////////////////////////////////////////////
43 | Other notes:
44 |
45 | AppWizard uses "TODO:" comments to indicate parts of the source code you
46 | should add to or customize.
47 |
48 | /////////////////////////////////////////////////////////////////////////////
49 |
--------------------------------------------------------------------------------
/NoxCap/bmem.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Hugh Bailey
3 | *
4 | * Permission to use, copy, modify, and distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 |
17 | #pragma once
18 |
19 |
20 | #include
21 | #include
22 |
23 | #include "c99defs.h"
24 | #ifdef __cplusplus
25 | extern "C" {
26 | #endif
27 |
28 | struct base_allocator {
29 | void *(*malloc)(size_t);
30 | void *(*realloc)(void *, size_t);
31 | void (*free)(void *);
32 | };
33 |
34 | EXPORT void base_set_allocator(struct base_allocator *defs);
35 |
36 | EXPORT void *bmalloc(size_t size);
37 | EXPORT void *brealloc(void *ptr, size_t size);
38 | EXPORT void bfree(void *ptr);
39 |
40 | EXPORT int base_get_alignment(void);
41 |
42 | EXPORT long bnum_allocs(void);
43 |
44 | EXPORT void *bmemdup(const void *ptr, size_t size);
45 |
46 | static inline void *bzalloc(size_t size)
47 | {
48 | void *mem = bmalloc(size);
49 | if (mem)
50 | memset(mem, 0, size);
51 | return mem;
52 | }
53 |
54 | static inline char *bstrdup_n(const char *str, size_t n)
55 | {
56 | char *dup;
57 | if (!str)
58 | return NULL;
59 |
60 | dup = (char *)bmemdup(str, n + 1);
61 | dup[n] = 0;
62 |
63 | return dup;
64 | }
65 |
66 | static inline wchar_t *bwstrdup_n(const wchar_t *str, size_t n)
67 | {
68 | wchar_t *dup;
69 | if (!str)
70 | return NULL;
71 |
72 | dup = (wchar_t *)bmemdup(str, (n + 1) * sizeof(wchar_t));
73 | dup[n] = 0;
74 |
75 | return dup;
76 | }
77 |
78 | static inline char *bstrdup(const char *str)
79 | {
80 | if (!str)
81 | return NULL;
82 |
83 | return bstrdup_n(str, strlen(str));
84 | }
85 |
86 | static inline wchar_t *bwstrdup(const wchar_t *str)
87 | {
88 | if (!str)
89 | return NULL;
90 |
91 | return bwstrdup_n(str, wcslen(str));
92 | }
93 |
94 | #ifdef __cplusplus
95 | }
96 | #endif
97 |
--------------------------------------------------------------------------------
/NoxCap/app-helpers.c:
--------------------------------------------------------------------------------
1 | #ifdef _MSC_VER
2 | #pragma warning(disable : 4152) /* casting func ptr to void */
3 | #endif
4 |
5 | #include
6 | #include
7 | #include "app-helpers.h"
8 | #include "nt-stuff.h"
9 |
10 | WINADVAPI WINAPI ConvertSidToStringSidW(PSID sid, LPWSTR *str);
11 | wchar_t *get_app_sid(HANDLE process);
12 | bool is_app(HANDLE process);
13 | HANDLE open_app_mutex(const wchar_t *sid, const wchar_t *name);
14 | HANDLE open_app_event(const wchar_t *sid, const wchar_t *name);
15 | HANDLE open_app_map(const wchar_t *sid, const wchar_t *name);
16 |
17 | bool is_app(HANDLE process)
18 | {
19 | DWORD size_ret;
20 | DWORD ret = 0;
21 | HANDLE token;
22 |
23 | if (OpenProcessToken(process, TOKEN_QUERY, &token)) {
24 | BOOL success = GetTokenInformation(token, TokenIsAppContainer,
25 | &ret, sizeof(ret),
26 | &size_ret);
27 | if (!success) {
28 | DWORD error = GetLastError();
29 | int test = 0;
30 | }
31 |
32 | CloseHandle(token);
33 | }
34 | return !!ret;
35 | }
36 |
37 | wchar_t *get_app_sid(HANDLE process)
38 | {
39 | wchar_t *ret = NULL;
40 | DWORD size_ret;
41 | BOOL success;
42 | HANDLE token;
43 |
44 | if (OpenProcessToken(process, TOKEN_QUERY, &token)) {
45 | DWORD info_len = GetSidLengthRequired(12) +
46 | sizeof(TOKEN_APPCONTAINER_INFORMATION);
47 |
48 | PTOKEN_APPCONTAINER_INFORMATION info = malloc(info_len);
49 |
50 | success = GetTokenInformation(token, TokenAppContainerSid, info,
51 | info_len, &size_ret);
52 | if (success)
53 | ConvertSidToStringSidW(info->TokenAppContainer, &ret);
54 |
55 | free(info);
56 | CloseHandle(token);
57 | }
58 |
59 | return ret;
60 | }
61 |
62 | static const wchar_t *path_format =
63 | L"\\Sessions\\%lu\\AppContainerNamedObjects\\%s\\%s";
64 |
65 | HANDLE open_app_mutex(const wchar_t *sid, const wchar_t *name)
66 | {
67 | wchar_t path[MAX_PATH];
68 | DWORD session_id = WTSGetActiveConsoleSessionId();
69 | _snwprintf(path, MAX_PATH, path_format, session_id, sid, name);
70 | return nt_open_mutex(path);
71 | }
72 |
73 | HANDLE open_app_event(const wchar_t *sid, const wchar_t *name)
74 | {
75 | wchar_t path[MAX_PATH];
76 | DWORD session_id = WTSGetActiveConsoleSessionId();
77 | _snwprintf(path, MAX_PATH, path_format, session_id, sid, name);
78 | return nt_open_event(path);
79 | }
80 |
81 | HANDLE open_app_map(const wchar_t *sid, const wchar_t *name)
82 | {
83 | wchar_t path[MAX_PATH];
84 | DWORD session_id = WTSGetActiveConsoleSessionId();
85 | _snwprintf(path, MAX_PATH, path_format, session_id, sid, name);
86 | return nt_open_map(path);
87 | }
88 |
--------------------------------------------------------------------------------
/NoxCap/semaphore.c:
--------------------------------------------------------------------------------
1 | /*
2 | * -------------------------------------------------------------
3 | *
4 | * Module: semaphore.c
5 | *
6 | * Purpose:
7 | * Concatenated version of separate modules to allow
8 | * inlining optimisation, which it is assumed can only
9 | * be effective within a single module.
10 | *
11 | * Semaphores aren't actually part of the PThreads standard.
12 | * They are defined by the POSIX Standard:
13 | *
14 | * POSIX 1003.1b-1993 (POSIX.1b)
15 | *
16 | * -------------------------------------------------------------
17 | *
18 | * --------------------------------------------------------------------------
19 | *
20 | * Pthreads-win32 - POSIX Threads Library for Win32
21 | * Copyright(C) 1998 John E. Bossom
22 | * Copyright(C) 1999,2005 Pthreads-win32 contributors
23 | *
24 | * Contact Email: rpj@callisto.canberra.edu.au
25 | *
26 | * The current list of contributors is contained
27 | * in the file CONTRIBUTORS included with the source
28 | * code distribution. The list can also be seen at the
29 | * following World Wide Web location:
30 | * http://sources.redhat.com/pthreads-win32/contributors.html
31 | *
32 | * This library is free software; you can redistribute it and/or
33 | * modify it under the terms of the GNU Lesser General Public
34 | * License as published by the Free Software Foundation; either
35 | * version 2 of the License, or (at your option) any later version.
36 | *
37 | * This library is distributed in the hope that it will be useful,
38 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
39 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
40 | * Lesser General Public License for more details.
41 | *
42 | * You should have received a copy of the GNU Lesser General Public
43 | * License along with this library in the file COPYING.LIB;
44 | * if not, write to the Free Software Foundation, Inc.,
45 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
46 | */
47 |
48 | #if !defined(NEED_FTIME)
49 | # include
50 | #endif
51 |
52 | #include
53 |
54 | #include "pthread.h"
55 | #include "semaphore.h"
56 | #include "implement.h"
57 |
58 |
59 | #include "sem_init.c"
60 | #include "sem_destroy.c"
61 | #include "sem_trywait.c"
62 | #include "sem_wait.c"
63 | #include "sem_timedwait.c"
64 | #include "sem_post.c"
65 | #include "sem_post_multiple.c"
66 | #include "sem_getvalue.c"
67 | #include "sem_open.c"
68 | #include "sem_close.c"
69 | #include "sem_unlink.c"
70 |
--------------------------------------------------------------------------------
/NoxCap/c99defs.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Hugh Bailey
3 | *
4 | * Permission to use, copy, modify, and distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 |
17 | #pragma once
18 |
19 | /*
20 | * Contains hacks for getting some C99 stuff working in VC, things like
21 | * bool, inline, stdint
22 | */
23 |
24 | #define UNUSED_PARAMETER(param) (void)param
25 |
26 | #ifdef _MSC_VER
27 | #define DEPRECATED __declspec(deprecated)
28 | #define FORCE_INLINE __forceinline
29 | #else
30 | #define DEPRECATED __attribute__((deprecated))
31 | #define FORCE_INLINE inline __attribute__((always_inline))
32 | #endif
33 |
34 | #ifdef _MSC_VER
35 |
36 | /* Microsoft is one of the most inept companies on the face of the planet.
37 | * The fact that even visual studio 2013 doesn't support the standard 'inline'
38 | * keyword is so incredibly stupid that I just can't imagine what sort of
39 | * incredibly inept moron could possibly be managing the visual C compiler
40 | * project. They should be fired, and legally forbidden to have a job in
41 | * ANYTHING even REMOTELY related to programming. FOREVER. This should also
42 | * apply to the next 10 generations all of their descendants. */
43 | #ifndef __cplusplus
44 | #define inline __inline
45 | #endif
46 |
47 | #define EXPORT __declspec(dllexport)
48 | #else
49 | #define EXPORT
50 | #endif
51 |
52 | #if _MSC_VER && _MSC_VER < 0x0708
53 |
54 | #include "vc/vc_stdint.h"
55 | #include "vc/vc_stdbool.h"
56 |
57 | #ifndef __off_t_defined
58 | #define __off_t_defined
59 | #if _FILE_OFFSET_BITS == 64
60 | typedef long long off_t;
61 | #else
62 | typedef long off_t;
63 | #endif
64 | typedef int64_t off64_t;
65 | #endif /* __off_t_defined */
66 |
67 | #define SIZE_T_FORMAT "%u"
68 |
69 | #else
70 |
71 | #include
72 | #include
73 | #include
74 | #include
75 |
76 | #define SIZE_T_FORMAT "%zu"
77 |
78 | #endif /* _MSC_VER */
79 |
--------------------------------------------------------------------------------
/Nox/libOpenGL/gl-zstencil.c:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | Copyright (C) 2013 by Hugh Bailey
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 2 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | ******************************************************************************/
17 |
18 | #include "gl-subsystem.h"
19 |
20 | static bool gl_init_zsbuffer(struct gs_zstencil_buffer *zs, uint32_t width,
21 | uint32_t height)
22 | {
23 | glGenRenderbuffers(1, &zs->buffer);
24 | if (!gl_success("glGenRenderbuffers"))
25 | return false;
26 |
27 | if (!gl_bind_renderbuffer(GL_RENDERBUFFER, zs->buffer))
28 | return false;
29 |
30 | glRenderbufferStorage(GL_RENDERBUFFER, zs->format, width, height);
31 | if (!gl_success("glRenderbufferStorage"))
32 | return false;
33 |
34 | gl_bind_renderbuffer(GL_RENDERBUFFER, 0);
35 | return true;
36 | }
37 |
38 | static inline GLenum get_attachment(enum gs_zstencil_format format)
39 | {
40 | switch (format) {
41 | case GS_Z16:
42 | return GL_DEPTH_ATTACHMENT;
43 | case GS_Z24_S8:
44 | return GL_DEPTH_STENCIL_ATTACHMENT;
45 | case GS_Z32F:
46 | return GL_DEPTH_ATTACHMENT;
47 | case GS_Z32F_S8X24:
48 | return GL_DEPTH_STENCIL_ATTACHMENT;
49 | case GS_ZS_NONE:
50 | return 0;
51 | }
52 |
53 | return 0;
54 | }
55 |
56 | gs_zstencil_t *device_zstencil_create(gs_device_t *device, uint32_t width,
57 | uint32_t height,
58 | enum gs_zstencil_format format)
59 | {
60 | struct gs_zstencil_buffer *zs;
61 |
62 | zs = bzalloc(sizeof(struct gs_zstencil_buffer));
63 | zs->format = convert_zstencil_format(format);
64 | zs->attachment = get_attachment(format);
65 | zs->device = device;
66 |
67 | if (!gl_init_zsbuffer(zs, width, height)) {
68 | blog(LOG_ERROR, "device_zstencil_create (GL) failed");
69 | gs_zstencil_destroy(zs);
70 | return NULL;
71 | }
72 |
73 | return zs;
74 | }
75 |
76 | void gs_zstencil_destroy(gs_zstencil_t *zs)
77 | {
78 | if (zs) {
79 | if (zs->buffer) {
80 | glDeleteRenderbuffers(1, &zs->buffer);
81 | gl_success("glDeleteRenderbuffers");
82 | }
83 |
84 | bfree(zs);
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/NoxCap/ReadMe.txt:
--------------------------------------------------------------------------------
1 | ========================================================================
2 | WIN32 APPLICATION : Nox Project Overview
3 | ========================================================================
4 |
5 | AppWizard has created this Nox application for you.
6 |
7 | This file contains a summary of what you will find in each of the files that
8 | make up your Nox application.
9 |
10 |
11 | Nox.vcxproj
12 | This is the main project file for VC++ projects generated using an Application Wizard.
13 | It contains information about the version of Visual C++ that generated the file, and
14 | information about the platforms, configurations, and project features selected with the
15 | Application Wizard.
16 |
17 | Nox.vcxproj.filters
18 | This is the filters file for VC++ projects generated using an Application Wizard.
19 | It contains information about the association between the files in your project
20 | and the filters. This association is used in the IDE to show grouping of files with
21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the
22 | "Source Files" filter).
23 |
24 | Nox.cpp
25 | This is the main application source file.
26 |
27 | /////////////////////////////////////////////////////////////////////////////
28 | AppWizard has created the following resources:
29 |
30 | Nox.rc
31 | This is a listing of all of the Microsoft Windows resources that the
32 | program uses. It includes the icons, bitmaps, and cursors that are stored
33 | in the RES subdirectory. This file can be directly edited in Microsoft
34 | Visual C++.
35 |
36 | Resource.h
37 | This is the standard header file, which defines new resource IDs.
38 | Microsoft Visual C++ reads and updates this file.
39 |
40 | Nox.ico
41 | This is an icon file, which is used as the application's icon (32x32).
42 | This icon is included by the main resource file Nox.rc.
43 |
44 | small.ico
45 | This is an icon file, which contains a smaller version (16x16)
46 | of the application's icon. This icon is included by the main resource
47 | file Nox.rc.
48 |
49 | /////////////////////////////////////////////////////////////////////////////
50 | Other standard files:
51 |
52 | StdAfx.h, StdAfx.cpp
53 | These files are used to build a precompiled header (PCH) file
54 | named Nox.pch and a precompiled types file named StdAfx.obj.
55 |
56 | /////////////////////////////////////////////////////////////////////////////
57 | Other notes:
58 |
59 | AppWizard uses "TODO:" comments to indicate parts of the source code you
60 | should add to or customize.
61 |
62 | /////////////////////////////////////////////////////////////////////////////
63 |
--------------------------------------------------------------------------------
/NoxCap/threading.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013-2014 Hugh Bailey
3 | *
4 | * Permission to use, copy, modify, and distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 |
17 | #pragma once
18 |
19 | /*
20 | * Allows posix thread usage on windows as well as other operating systems.
21 | * Use this header if you want to make your code more platform independent.
22 | *
23 | * Also provides a custom platform-independent "event" handler via
24 | * pthread conditional waits.
25 | */
26 |
27 | #include "c99defs.h"
28 |
29 | #ifdef _MSC_VER
30 | #include "pthread.h"
31 | #else
32 | #include
33 | #include
34 | #endif
35 |
36 | #ifdef __cplusplus
37 | extern "C" {
38 | #endif
39 |
40 | #ifdef _WIN32
41 | #include "threading-windows.h"
42 | #else
43 | #include "threading-posix.h"
44 | #endif
45 |
46 | /* this may seem strange, but you can't use it unless it's an initializer */
47 | static inline void pthread_mutex_init_value(pthread_mutex_t *mutex)
48 | {
49 | pthread_mutex_t init_val = PTHREAD_MUTEX_INITIALIZER;
50 | if (!mutex)
51 | return;
52 |
53 | *mutex = init_val;
54 | }
55 |
56 | enum os_event_type {
57 | OS_EVENT_TYPE_AUTO,
58 | OS_EVENT_TYPE_MANUAL,
59 | };
60 |
61 | struct os_event_data;
62 | struct os_sem_data;
63 | typedef struct os_event_data os_event_t;
64 | typedef struct os_sem_data os_sem_t;
65 |
66 | EXPORT int os_event_init(os_event_t **event, enum os_event_type type);
67 | EXPORT void os_event_destroy(os_event_t *event);
68 | EXPORT int os_event_wait(os_event_t *event);
69 | EXPORT int os_event_timedwait(os_event_t *event, unsigned long milliseconds);
70 | EXPORT int os_event_try(os_event_t *event);
71 | EXPORT int os_event_signal(os_event_t *event);
72 | EXPORT void os_event_reset(os_event_t *event);
73 |
74 | EXPORT int os_sem_init(os_sem_t **sem, int value);
75 | EXPORT void os_sem_destroy(os_sem_t *sem);
76 | EXPORT int os_sem_post(os_sem_t *sem);
77 | EXPORT int os_sem_wait(os_sem_t *sem);
78 |
79 | EXPORT void os_set_thread_name(const char *name);
80 |
81 | #ifdef _MSC_VER
82 | #define THREAD_LOCAL __declspec(thread)
83 | #else
84 | #define THREAD_LOCAL __thread
85 | #endif
86 |
87 | #ifdef __cplusplus
88 | }
89 | #endif
90 |
--------------------------------------------------------------------------------
/Nox/graphics-hook-info.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #include "hook-helpers.h"
12 |
13 | #define EVENT_CAPTURE_RESTART L"CaptureHook_Restart"
14 | #define EVENT_CAPTURE_STOP L"CaptureHook_Stop"
15 |
16 | #define EVENT_HOOK_READY L"CaptureHook_HookReady"
17 | #define EVENT_HOOK_EXIT L"CaptureHook_Exit"
18 |
19 | #define EVENT_HOOK_INIT L"CaptureHook_Initialize"
20 |
21 | #define WINDOW_HOOK_KEEPALIVE L"CaptureHook_KeepAlive"
22 |
23 | #define MUTEX_TEXTURE1 L"CaptureHook_TextureMutex1"
24 | #define MUTEX_TEXTURE2 L"CaptureHook_TextureMutex2"
25 |
26 | #define SHMEM_HOOK_INFO L"CaptureHook_HookInfo"
27 | #define SHMEM_TEXTURE L"CaptureHook_Texture"
28 |
29 | #define PIPE_NAME "CaptureHook_Pipe"
30 |
31 | #pragma pack(push, 8)
32 |
33 | struct d3d8_offsets {
34 | uint32_t present;
35 | };
36 |
37 | struct d3d9_offsets {
38 | uint32_t present;
39 | uint32_t present_ex;
40 | uint32_t present_swap;
41 | uint32_t d3d9_clsoff;
42 | uint32_t is_d3d9ex_clsoff;
43 | };
44 |
45 | struct dxgi_offsets {
46 | uint32_t present;
47 | uint32_t resize;
48 |
49 | uint32_t present1;
50 | };
51 |
52 | struct ddraw_offsets {
53 | uint32_t surface_create;
54 | uint32_t surface_restore;
55 | uint32_t surface_release;
56 | uint32_t surface_unlock;
57 | uint32_t surface_blt;
58 | uint32_t surface_flip;
59 | uint32_t surface_set_palette;
60 | uint32_t palette_set_entries;
61 | };
62 |
63 | struct shmem_data {
64 | volatile int last_tex;
65 | uint32_t tex1_offset;
66 | uint32_t tex2_offset;
67 | };
68 |
69 | struct shtex_data {
70 | uint32_t tex_handle;
71 | };
72 |
73 | enum capture_type {
74 | CAPTURE_TYPE_MEMORY,
75 | CAPTURE_TYPE_TEXTURE,
76 | };
77 |
78 | struct graphics_offsets {
79 | struct d3d8_offsets d3d8;
80 | struct d3d9_offsets d3d9;
81 | struct dxgi_offsets dxgi;
82 | struct ddraw_offsets ddraw;
83 | };
84 |
85 | struct hook_info {
86 | /* capture info */
87 | enum capture_type type;
88 | uint32_t window;
89 | uint32_t format;
90 | uint32_t cx;
91 | uint32_t cy;
92 | uint32_t base_cx;
93 | uint32_t base_cy;
94 | uint32_t pitch;
95 | uint32_t map_id;
96 | uint32_t map_size;
97 | bool flip;
98 |
99 | /* additional options */
100 | uint64_t frame_interval;
101 | bool use_scale;
102 | bool force_shmem;
103 | bool capture_overlay;
104 |
105 | /* hook addresses */
106 | struct graphics_offsets offsets;
107 | };
108 |
109 | #pragma pack(pop)
110 |
111 | #define GC_MAPPING_FLAGS (FILE_MAP_READ | FILE_MAP_WRITE)
112 |
113 | static inline HANDLE create_hook_info(DWORD id)
114 | {
115 | wchar_t new_name[64];
116 | _snwprintf(new_name, 64, L"%s%lu", SHMEM_HOOK_INFO, id);
117 |
118 | return CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
119 | sizeof(struct hook_info), new_name);
120 | }
121 |
--------------------------------------------------------------------------------
/Nox/libOpenGL/gl-shaderparser.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | Copyright (C) 2013 by Hugh Bailey
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 2 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | ******************************************************************************/
17 |
18 | #pragma once
19 |
20 | /*
21 | * Parses shaders into GLSL. Shaders are almost identical to HLSL
22 | * model 5 so it requires quite a bit of tweaking to convert correctly.
23 | * Takes the parsed shader data, and builds a GLSL string out of it.
24 | */
25 |
26 | #include
27 | #include
28 |
29 | struct gl_parser_attrib {
30 | struct dstr name;
31 | const char *mapping;
32 | bool input;
33 | };
34 |
35 | static inline void gl_parser_attrib_init(struct gl_parser_attrib *attr)
36 | {
37 | memset(attr, 0, sizeof(struct gl_parser_attrib));
38 | }
39 |
40 | static inline void gl_parser_attrib_free(struct gl_parser_attrib *attr)
41 | {
42 | dstr_free(&attr->name);
43 | }
44 |
45 | struct gl_shader_parser {
46 | enum gs_shader_type type;
47 | const char *input_prefix;
48 | const char *output_prefix;
49 | struct shader_parser parser;
50 | struct dstr gl_string;
51 |
52 | DARRAY(uint32_t) texture_samplers;
53 | DARRAY(struct gl_parser_attrib) attribs;
54 | };
55 |
56 | static inline void gl_shader_parser_init(struct gl_shader_parser *glsp,
57 | enum gs_shader_type type)
58 | {
59 | glsp->type = type;
60 |
61 | if (type == GS_SHADER_VERTEX) {
62 | glsp->input_prefix = "_input_attrib";
63 | glsp->output_prefix = "_vertex_shader_attrib";
64 | } else if (type == GS_SHADER_PIXEL) {
65 | glsp->input_prefix = "_vertex_shader_attrib";
66 | glsp->output_prefix = "_pixel_shader_attrib";
67 | }
68 |
69 | shader_parser_init(&glsp->parser);
70 | dstr_init(&glsp->gl_string);
71 | da_init(glsp->texture_samplers);
72 | da_init(glsp->attribs);
73 | }
74 |
75 | static inline void gl_shader_parser_free(struct gl_shader_parser *glsp)
76 | {
77 | size_t i;
78 | for (i = 0; i < glsp->attribs.num; i++)
79 | gl_parser_attrib_free(glsp->attribs.array + i);
80 |
81 | da_free(glsp->attribs);
82 | da_free(glsp->texture_samplers);
83 | dstr_free(&glsp->gl_string);
84 | shader_parser_free(&glsp->parser);
85 | }
86 |
87 | extern bool gl_shader_parse(struct gl_shader_parser *glsp,
88 | const char *shader_str, const char *file);
89 |
--------------------------------------------------------------------------------
/NoxCap/Nox.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Header Files
23 |
24 |
25 | Header Files
26 |
27 |
28 | Header Files
29 |
30 |
31 | Header Files
32 |
33 |
34 | Header Files
35 |
36 |
37 | Header Files
38 |
39 |
40 | Header Files
41 |
42 |
43 | Header Files
44 |
45 |
46 | Header Files
47 |
48 |
49 | Header Files
50 |
51 |
52 | Header Files
53 |
54 |
55 |
56 |
57 | Source Files
58 |
59 |
60 | Source Files
61 |
62 |
63 | Source Files
64 |
65 |
66 | Source Files
67 |
68 |
69 | Source Files
70 |
71 |
72 | Source Files
73 |
74 |
75 |
76 |
77 | Resource Files
78 |
79 |
80 |
81 |
82 | Resource Files
83 |
84 |
85 | Resource Files
86 |
87 |
88 | Resource Files
89 |
90 |
91 |
--------------------------------------------------------------------------------
/Nox/libOpenGL/gl-indexbuffer.c:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | Copyright (C) 2013 by Hugh Bailey
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 2 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | ******************************************************************************/
17 |
18 | #include "gl-subsystem.h"
19 |
20 | static inline bool init_ib(struct gs_index_buffer *ib)
21 | {
22 | GLenum usage = ib->dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW;
23 | bool success;
24 |
25 | success = gl_create_buffer(GL_ELEMENT_ARRAY_BUFFER, &ib->buffer,
26 | ib->size, ib->data, usage);
27 |
28 | if (!ib->dynamic) {
29 | bfree(ib->data);
30 | ib->data = NULL;
31 | }
32 |
33 | return success;
34 | }
35 |
36 | gs_indexbuffer_t *device_indexbuffer_create(gs_device_t *device,
37 | enum gs_index_type type,
38 | void *indices, size_t num,
39 | uint32_t flags)
40 | {
41 | struct gs_index_buffer *ib = bzalloc(sizeof(struct gs_index_buffer));
42 | size_t width = type == GS_UNSIGNED_LONG ? 4 : 2;
43 |
44 | ib->device = device;
45 | ib->data = indices;
46 | ib->dynamic = flags & GS_DYNAMIC;
47 | ib->num = num;
48 | ib->width = width;
49 | ib->size = width * num;
50 | ib->type = type;
51 | ib->gl_type = type == GS_UNSIGNED_LONG ? GL_UNSIGNED_INT
52 | : GL_UNSIGNED_SHORT;
53 |
54 | if (!init_ib(ib)) {
55 | blog(LOG_ERROR, "device_indexbuffer_create (GL) failed");
56 | gs_indexbuffer_destroy(ib);
57 | return NULL;
58 | }
59 |
60 | return ib;
61 | }
62 |
63 | void gs_indexbuffer_destroy(gs_indexbuffer_t *ib)
64 | {
65 | if (ib) {
66 | if (ib->buffer)
67 | gl_delete_buffers(1, &ib->buffer);
68 |
69 | bfree(ib->data);
70 | bfree(ib);
71 | }
72 | }
73 |
74 | static inline void gs_indexbuffer_flush_internal(gs_indexbuffer_t *ib,
75 | const void *data)
76 | {
77 | if (!ib->dynamic) {
78 | blog(LOG_ERROR, "Index buffer is not dynamic");
79 | goto fail;
80 | }
81 |
82 | if (!update_buffer(GL_ELEMENT_ARRAY_BUFFER, ib->buffer, data, ib->size))
83 | goto fail;
84 |
85 | return;
86 |
87 | fail:
88 | blog(LOG_ERROR, "gs_indexbuffer_flush (GL) failed");
89 | }
90 |
91 | void gs_indexbuffer_flush(gs_indexbuffer_t *ib)
92 | {
93 | gs_indexbuffer_flush_internal(ib, ib->data);
94 | }
95 |
96 | void gs_indexbuffer_flush_direct(gs_indexbuffer_t *ib, const void *data)
97 | {
98 | gs_indexbuffer_flush_internal(ib, data);
99 | }
100 |
101 | void *gs_indexbuffer_get_data(const gs_indexbuffer_t *ib)
102 | {
103 | return ib->data;
104 | }
105 |
106 | size_t gs_indexbuffer_get_num_indices(const gs_indexbuffer_t *ib)
107 | {
108 | return ib->num;
109 | }
110 |
111 | enum gs_index_type gs_indexbuffer_get_type(const gs_indexbuffer_t *ib)
112 | {
113 | return ib->type;
114 | }
115 |
116 | void device_load_indexbuffer(gs_device_t *device, gs_indexbuffer_t *ib)
117 | {
118 | device->cur_index_buffer = ib;
119 | }
120 |
--------------------------------------------------------------------------------
/NoxCap/bmem.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Hugh Bailey
3 | *
4 | * Permission to use, copy, modify, and distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 |
17 | #include
18 | #include
19 | //#include "base.h"
20 | #include "bmem.h"
21 | //#include "platform.h"
22 | #include "threading.h"
23 |
24 | /*
25 | * NOTE: totally jacked the mem alignment trick from ffmpeg, credit to them:
26 | * http://www.ffmpeg.org/
27 | */
28 |
29 | #define ALIGNMENT 32
30 |
31 | /* TODO: use memalign for non-windows systems */
32 | #if defined(_WIN32)
33 | #define ALIGNED_MALLOC 1
34 | #else
35 | #define ALIGNMENT_HACK 1
36 | #endif
37 |
38 | static void *a_malloc(size_t size)
39 | {
40 | #ifdef ALIGNED_MALLOC
41 | return _aligned_malloc(size, ALIGNMENT);
42 | #elif ALIGNMENT_HACK
43 | void *ptr = NULL;
44 | long diff;
45 |
46 | ptr = malloc(size + ALIGNMENT);
47 | if (ptr) {
48 | diff = ((~(long)ptr) & (ALIGNMENT - 1)) + 1;
49 | ptr = (char *)ptr + diff;
50 | ((char *)ptr)[-1] = (char)diff;
51 | }
52 |
53 | return ptr;
54 | #else
55 | return malloc(size);
56 | #endif
57 | }
58 |
59 | static void *a_realloc(void *ptr, size_t size)
60 | {
61 | #ifdef ALIGNED_MALLOC
62 | return _aligned_realloc(ptr, size, ALIGNMENT);
63 | #elif ALIGNMENT_HACK
64 | long diff;
65 |
66 | if (!ptr)
67 | return a_malloc(size);
68 | diff = ((char *)ptr)[-1];
69 | ptr = realloc((char *)ptr - diff, size + diff);
70 | if (ptr)
71 | ptr = (char *)ptr + diff;
72 | return ptr;
73 | #else
74 | return realloc(ptr, size);
75 | #endif
76 | }
77 |
78 | static void a_free(void *ptr)
79 | {
80 | #ifdef ALIGNED_MALLOC
81 | _aligned_free(ptr);
82 | #elif ALIGNMENT_HACK
83 | if (ptr)
84 | free((char *)ptr - ((char *)ptr)[-1]);
85 | #else
86 | free(ptr);
87 | #endif
88 | }
89 |
90 | static struct base_allocator alloc = {a_malloc, a_realloc, a_free};
91 | static long num_allocs = 0;
92 |
93 | void base_set_allocator(struct base_allocator *defs)
94 | {
95 | memcpy(&alloc, defs, sizeof(struct base_allocator));
96 | }
97 |
98 | void *bmalloc(size_t size)
99 | {
100 | void *ptr = alloc.malloc(size);
101 | if (!ptr && !size)
102 | ptr = alloc.malloc(1);
103 | if (!ptr) {
104 | os_breakpoint();
105 | bcrash("Out of memory while trying to allocate %lu bytes",
106 | (unsigned long)size);
107 | }
108 |
109 | os_atomic_inc_long(&num_allocs);
110 | return ptr;
111 | }
112 |
113 | void *brealloc(void *ptr, size_t size)
114 | {
115 | if (!ptr)
116 | os_atomic_inc_long(&num_allocs);
117 |
118 | ptr = alloc.realloc(ptr, size);
119 | if (!ptr && !size)
120 | ptr = alloc.realloc(ptr, 1);
121 | if (!ptr) {
122 | os_breakpoint();
123 | bcrash("Out of memory while trying to allocate %lu bytes",
124 | (unsigned long)size);
125 | }
126 |
127 | return ptr;
128 | }
129 |
130 | void bfree(void *ptr)
131 | {
132 | if (ptr)
133 | os_atomic_dec_long(&num_allocs);
134 | alloc.free(ptr);
135 | }
136 |
137 | long bnum_allocs(void)
138 | {
139 | return num_allocs;
140 | }
141 |
142 | int base_get_alignment(void)
143 | {
144 | return ALIGNMENT;
145 | }
146 |
147 | void *bmemdup(const void *ptr, size_t size)
148 | {
149 | void *out = bmalloc(size);
150 | if (size)
151 | memcpy(out, ptr, size);
152 |
153 | return out;
154 | }
155 |
--------------------------------------------------------------------------------
/Nox/Noxcap.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Header Files
23 |
24 |
25 | Header Files
26 |
27 |
28 | Header Files
29 |
30 |
31 | Header Files
32 |
33 |
34 | Header Files
35 |
36 |
37 | Header Files
38 |
39 |
40 | Header Files
41 |
42 |
43 | Header Files
44 |
45 |
46 | Header Files
47 |
48 |
49 | Header Files
50 |
51 |
52 | Header Files
53 |
54 |
55 | Header Files
56 |
57 |
58 | Header Files
59 |
60 |
61 | Header Files
62 |
63 |
64 | Header Files
65 |
66 |
67 |
68 |
69 | Source Files
70 |
71 |
72 | Source Files
73 |
74 |
75 | Source Files
76 |
77 |
78 | Source Files
79 |
80 |
81 | Source Files
82 |
83 |
84 | Source Files
85 |
86 |
87 | Source Files
88 |
89 |
90 | Source Files
91 |
92 |
93 | Source Files
94 |
95 |
96 | Source Files
97 |
98 |
99 | Source Files
100 |
101 |
102 |
--------------------------------------------------------------------------------
/Nox/libOpenGL/gl-texturecube.c:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | Copyright (C) 2013 by Hugh Bailey
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 2 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | ******************************************************************************/
17 |
18 | #include "gl-subsystem.h"
19 |
20 | static inline bool upload_texture_cube(struct gs_texture_cube *tex,
21 | const uint8_t **data)
22 | {
23 | uint32_t row_size = tex->size * gs_get_format_bpp(tex->base.format);
24 | uint32_t tex_size = tex->size * row_size / 8;
25 | uint32_t num_levels = tex->base.levels;
26 | bool compressed = gs_is_compressed_format(tex->base.format);
27 | GLenum gl_type = get_gl_format_type(tex->base.format);
28 | bool success = true;
29 | uint32_t i;
30 |
31 | if (!num_levels)
32 | num_levels = gs_get_total_levels(tex->size, tex->size);
33 |
34 | for (i = 0; i < 6; i++) {
35 | GLenum target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
36 |
37 | if (!gl_bind_texture(target, tex->base.texture))
38 | success = false;
39 |
40 | if (!gl_init_face(target, gl_type, num_levels,
41 | tex->base.gl_format,
42 | tex->base.gl_internal_format, compressed,
43 | tex->size, tex->size, tex_size, &data))
44 | success = false;
45 |
46 | if (!gl_bind_texture(target, 0))
47 | success = false;
48 |
49 | if (data)
50 | data++;
51 | }
52 |
53 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, num_levels);
54 | if (!gl_success("glTexParameteri"))
55 | success = false;
56 |
57 | return success;
58 | }
59 |
60 | gs_texture_t *device_cubetexture_create(gs_device_t *device, uint32_t size,
61 | enum gs_color_format color_format,
62 | uint32_t levels, const uint8_t **data,
63 | uint32_t flags)
64 | {
65 | struct gs_texture_cube *tex = bzalloc(sizeof(struct gs_texture_cube));
66 | tex->base.device = device;
67 | tex->base.type = GS_TEXTURE_CUBE;
68 | tex->base.format = color_format;
69 | tex->base.levels = levels;
70 | tex->base.gl_format = convert_gs_format(color_format);
71 | tex->base.gl_internal_format = convert_gs_internal_format(color_format);
72 | tex->base.gl_target = GL_TEXTURE_CUBE_MAP;
73 | tex->base.is_render_target = (flags & GS_RENDER_TARGET) != 0;
74 | tex->base.gen_mipmaps = (flags & GS_BUILD_MIPMAPS) != 0;
75 | tex->size = size;
76 |
77 | if (!gl_gen_textures(1, &tex->base.texture))
78 | goto fail;
79 | if (!upload_texture_cube(tex, data))
80 | goto fail;
81 |
82 | return (gs_texture_t *)tex;
83 |
84 | fail:
85 | gs_cubetexture_destroy((gs_texture_t *)tex);
86 | blog(LOG_ERROR, "device_cubetexture_create (GL) failed");
87 | return NULL;
88 | }
89 |
90 | void gs_cubetexture_destroy(gs_texture_t *tex)
91 | {
92 | if (!tex)
93 | return;
94 |
95 | if (tex->texture)
96 | gl_delete_textures(1, &tex->texture);
97 |
98 | if (tex->fbo)
99 | fbo_info_destroy(tex->fbo);
100 |
101 | bfree(tex);
102 | }
103 |
104 | static inline bool is_texture_cube(const gs_texture_t *tex, const char *func)
105 | {
106 | bool is_texcube = tex->type == GS_TEXTURE_CUBE;
107 | if (!is_texcube)
108 | blog(LOG_ERROR, "%s (GL) failed: Not a cubemap texture", func);
109 | return is_texcube;
110 | }
111 |
112 | uint32_t gs_cubetexture_get_size(const gs_texture_t *cubetex)
113 | {
114 | const struct gs_texture_cube *cube =
115 | (const struct gs_texture_cube *)cubetex;
116 |
117 | if (!is_texture_cube(cubetex, "gs_cubetexture_get_size"))
118 | return 0;
119 |
120 | return cube->size;
121 | }
122 |
123 | enum gs_color_format
124 | gs_cubetexture_get_color_format(const gs_texture_t *cubetex)
125 | {
126 | return cubetex->format;
127 | }
128 |
--------------------------------------------------------------------------------
/Nox/graphic-hook/d3d9-patches.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #ifdef __MINGW32__
6 | #include
7 | #ifndef TRYLEVEL_NONE
8 | #ifndef __MINGW64__
9 | #define NO_SEH_MINGW
10 | #endif
11 | #ifndef __try
12 | #define __try
13 | #endif
14 | #ifndef __except
15 | #define __except (x) if (0)
16 | #endif
17 | #endif
18 | #endif
19 |
20 | static inline int safe_memcmp(const void *p1, const void *p2, size_t size)
21 | {
22 |
23 | // Disabled exceptions on mingw-w64 as it is broken
24 | #ifndef __MINGW32__
25 | #ifdef NO_SEH_MINGW
26 | __try1(EXCEPTION_EXECUTE_HANDLER)
27 | #else
28 | __try
29 | #endif
30 | #endif
31 | {
32 | return memcmp(p1, p2, size);
33 | }
34 | // Disabled exceptions on mingw-w64 as it is broken
35 | #ifndef __MINGW32__
36 | #ifdef NO_SEH_MINGW
37 | __except1
38 | #else
39 | __except (EXCEPTION_EXECUTE_HANDLER)
40 | #endif
41 | {
42 | return -1;
43 | }
44 | #endif
45 | }
46 |
47 | struct patch_info {
48 | size_t size;
49 | const BYTE *data;
50 | };
51 |
52 | #define NEW_PATCH(x) \
53 | { \
54 | sizeof(x), (x) \
55 | }
56 | #define MAX_PATCH_SIZE 2
57 |
58 | static const BYTE force_jump[] = {0xEB};
59 | static const BYTE ignore_jump[] = {0x90, 0x90};
60 |
61 | #ifdef _WIN64
62 |
63 | #define NUM_VERS (16)
64 | #define CMP_SIZE (13)
65 |
66 |
67 | #else
68 |
69 | #define NUM_VERS (16)
70 | #define CMP_SIZE (12)
71 |
72 | static const uintptr_t patch_offset[NUM_VERS] = {
73 | 0x79AA6, //win7 - 6.1.7601.16562
74 | 0x79C9E, //win7 - 6.1.7600.16385
75 | 0x79D96, //win7 - 6.1.7601.17514
76 | 0x7F9BD, //win8.1 - 6.3.9431.00000
77 | 0x8A3F4, //win8.1 - 6.3.9600.16404
78 | 0x8B15F, //win10 - 10.0.10240.16384
79 | 0x8B19F, //win10 - 10.0.10162.0
80 | 0x8B83F, //win10 - 10.0.10240.16412
81 | 0x8E9F7, //win8.1 - 6.3.9600.17095
82 | 0x8F00F, //win8.1 - 6.3.9600.17085
83 | 0x8FBB1, //win8.1 - 6.3.9600.16384
84 | 0x90264, //win8.1 - 6.3.9600.17415
85 | 0x90C3A, //win10 - 10.0.10586.494
86 | 0x90C57, //win10 - 10.0.10586.0
87 | 0x96673, //win10 - 10.0.14393.0
88 | 0x166A08 //win8 - 6.2.9200.16384
89 | };
90 |
91 | static const uint8_t patch_cmp[NUM_VERS][CMP_SIZE] = {
92 | {0x8b, 0x89, 0xe8, 0x29, 0x00, 0x00, 0x39, 0xb9, 0x80, 0x4b, 0x00,
93 | 0x00},
94 | {0x8b, 0x89, 0xe8, 0x29, 0x00, 0x00, 0x39, 0xb9, 0x80, 0x4b, 0x00,
95 | 0x00},
96 | {0x8b, 0x89, 0xe8, 0x29, 0x00, 0x00, 0x39, 0xb9, 0x80, 0x4b, 0x00,
97 | 0x00},
98 | {0x8b, 0x80, 0xe8, 0x29, 0x00, 0x00, 0x39, 0xb0, 0x40, 0x4c, 0x00,
99 | 0x00},
100 | {0x80, 0xe8, 0x29, 0x00, 0x00, 0x83, 0xb8, 0x40, 0x4c, 0x00, 0x00,
101 | 0x00},
102 | {0x81, 0xe8, 0x29, 0x00, 0x00, 0x83, 0xb8, 0xa0, 0x4c, 0x00, 0x00,
103 | 0x00},
104 | {0x81, 0xe8, 0x29, 0x00, 0x00, 0x83, 0xb8, 0xa0, 0x4c, 0x00, 0x00,
105 | 0x00},
106 | {0x81, 0xe8, 0x29, 0x00, 0x00, 0x83, 0xb8, 0xa0, 0x4c, 0x00, 0x00,
107 | 0x00},
108 | {0x80, 0xe8, 0x29, 0x00, 0x00, 0x83, 0xb8, 0x40, 0x4c, 0x00, 0x00,
109 | 0x00},
110 | {0x80, 0xe8, 0x29, 0x00, 0x00, 0x83, 0xb8, 0x40, 0x4c, 0x00, 0x00,
111 | 0x00},
112 | {0x80, 0xe8, 0x29, 0x00, 0x00, 0x83, 0xb8, 0x40, 0x4c, 0x00, 0x00,
113 | 0x00},
114 | {0x87, 0xe8, 0x29, 0x00, 0x00, 0x83, 0xb8, 0x40, 0x4c, 0x00, 0x00,
115 | 0x00},
116 | {0x81, 0x18, 0x2a, 0x00, 0x00, 0x83, 0xb8, 0xa0, 0x4c, 0x00, 0x00,
117 | 0x00},
118 | {0x81, 0x18, 0x2a, 0x00, 0x00, 0x83, 0xb8, 0xa0, 0x4c, 0x00, 0x00,
119 | 0x00},
120 | {0x81, 0x18, 0x2a, 0x00, 0x00, 0x83, 0xb8, 0xa8, 0x4c, 0x00, 0x00,
121 | 0x00},
122 | {0x8b, 0x80, 0xe8, 0x29, 0x00, 0x00, 0x39, 0x90, 0xb0, 0x4b, 0x00,
123 | 0x00},
124 | };
125 |
126 | static const struct patch_info patch[NUM_VERS] = {
127 | NEW_PATCH(force_jump), NEW_PATCH(force_jump), NEW_PATCH(force_jump),
128 | NEW_PATCH(force_jump), NEW_PATCH(force_jump), NEW_PATCH(ignore_jump),
129 | NEW_PATCH(ignore_jump), NEW_PATCH(ignore_jump), NEW_PATCH(force_jump),
130 | NEW_PATCH(force_jump), NEW_PATCH(force_jump), NEW_PATCH(ignore_jump),
131 | NEW_PATCH(ignore_jump), NEW_PATCH(ignore_jump), NEW_PATCH(ignore_jump),
132 | NEW_PATCH(force_jump),
133 | };
134 |
135 | #endif
136 |
137 | static inline int get_d3d9_patch(HMODULE d3d9)
138 | {
139 | uint8_t *addr = (uint8_t *)d3d9;
140 | for (int i = 0; i < NUM_VERS; i++) {
141 | int ret = safe_memcmp(addr + patch_offset[i], patch_cmp[i],
142 | CMP_SIZE);
143 | if (ret == 0)
144 | return i;
145 | }
146 |
147 | return -1;
148 | }
149 |
150 | static inline uint8_t *get_d3d9_patch_addr(HMODULE d3d9, int patch)
151 | {
152 | if (patch == -1)
153 | return nullptr;
154 |
155 | uint8_t *addr = (uint8_t *)d3d9;
156 | return addr + patch_offset[patch] + CMP_SIZE;
157 | }
158 |
--------------------------------------------------------------------------------
/NoxCap/threading-windows.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Hugh Bailey
3 | *
4 | * Permission to use, copy, modify, and distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 |
17 | #include "bmem.h"
18 | #include "threading.h"
19 |
20 | #define WIN32_LEAN_AND_MEAN
21 | #include
22 |
23 | #ifdef __MINGW32__
24 | #include
25 | #ifndef TRYLEVEL_NONE
26 | #ifndef __MINGW64__
27 | #define NO_SEH_MINGW
28 | #endif
29 | #ifndef __try
30 | #define __try
31 | #endif
32 | #ifndef __except
33 | #define __except (x) if (0)
34 | #endif
35 | #endif
36 | #endif
37 |
38 | int os_event_init(os_event_t **event, enum os_event_type type)
39 | {
40 | HANDLE handle;
41 |
42 | handle = CreateEvent(NULL, (type == OS_EVENT_TYPE_MANUAL), FALSE, NULL);
43 | if (!handle)
44 | return -1;
45 |
46 | *event = (os_event_t *)handle;
47 | return 0;
48 | }
49 |
50 | void os_event_destroy(os_event_t *event)
51 | {
52 | if (event)
53 | CloseHandle((HANDLE)event);
54 | }
55 |
56 | int os_event_wait(os_event_t *event)
57 | {
58 | DWORD code;
59 |
60 | if (!event)
61 | return EINVAL;
62 |
63 | code = WaitForSingleObject((HANDLE)event, INFINITE);
64 | if (code != WAIT_OBJECT_0)
65 | return EINVAL;
66 |
67 | return 0;
68 | }
69 |
70 | int os_event_timedwait(os_event_t *event, unsigned long milliseconds)
71 | {
72 | DWORD code;
73 |
74 | if (!event)
75 | return EINVAL;
76 |
77 | code = WaitForSingleObject((HANDLE)event, milliseconds);
78 | if (code == WAIT_TIMEOUT)
79 | return ETIMEDOUT;
80 | else if (code != WAIT_OBJECT_0)
81 | return EINVAL;
82 |
83 | return 0;
84 | }
85 |
86 | int os_event_try(os_event_t *event)
87 | {
88 | DWORD code;
89 |
90 | if (!event)
91 | return EINVAL;
92 |
93 | code = WaitForSingleObject((HANDLE)event, 0);
94 | if (code == WAIT_TIMEOUT)
95 | return EAGAIN;
96 | else if (code != WAIT_OBJECT_0)
97 | return EINVAL;
98 |
99 | return 0;
100 | }
101 |
102 | int os_event_signal(os_event_t *event)
103 | {
104 | if (!event)
105 | return EINVAL;
106 |
107 | if (!SetEvent((HANDLE)event))
108 | return EINVAL;
109 |
110 | return 0;
111 | }
112 |
113 | void os_event_reset(os_event_t *event)
114 | {
115 | if (!event)
116 | return;
117 |
118 | ResetEvent((HANDLE)event);
119 | }
120 |
121 | int os_sem_init(os_sem_t **sem, int value)
122 | {
123 | HANDLE handle = CreateSemaphore(NULL, (LONG)value, 0x7FFFFFFF, NULL);
124 | if (!handle)
125 | return -1;
126 |
127 | *sem = (os_sem_t *)handle;
128 | return 0;
129 | }
130 |
131 | void os_sem_destroy(os_sem_t *sem)
132 | {
133 | if (sem)
134 | CloseHandle((HANDLE)sem);
135 | }
136 |
137 | int os_sem_post(os_sem_t *sem)
138 | {
139 | if (!sem)
140 | return -1;
141 | return ReleaseSemaphore((HANDLE)sem, 1, NULL) ? 0 : -1;
142 | }
143 |
144 | int os_sem_wait(os_sem_t *sem)
145 | {
146 | DWORD ret;
147 |
148 | if (!sem)
149 | return -1;
150 | ret = WaitForSingleObject((HANDLE)sem, INFINITE);
151 | return (ret == WAIT_OBJECT_0) ? 0 : -1;
152 | }
153 |
154 | #define VC_EXCEPTION 0x406D1388
155 |
156 | #pragma pack(push, 8)
157 | struct vs_threadname_info {
158 | DWORD type; /* 0x1000 */
159 | const char *name;
160 | DWORD thread_id;
161 | DWORD flags;
162 | };
163 | #pragma pack(pop)
164 |
165 | #define THREADNAME_INFO_SIZE \
166 | (sizeof(struct vs_threadname_info) / sizeof(ULONG_PTR))
167 |
168 | void os_set_thread_name(const char *name)
169 | {
170 | #ifdef __MINGW32__
171 | UNUSED_PARAMETER(name);
172 | #else
173 | struct vs_threadname_info info;
174 | info.type = 0x1000;
175 | info.name = name;
176 | info.thread_id = GetCurrentThreadId();
177 | info.flags = 0;
178 |
179 | #ifdef NO_SEH_MINGW
180 | __try1(EXCEPTION_EXECUTE_HANDLER)
181 | {
182 | #else
183 | __try {
184 | #endif
185 | RaiseException(VC_EXCEPTION, 0, THREADNAME_INFO_SIZE,
186 | (ULONG_PTR *)&info);
187 | #ifdef NO_SEH_MINGW
188 | }
189 | __except1{
190 | #else
191 | } __except (EXCEPTION_EXECUTE_HANDLER) {
192 | #endif
193 | }
194 | #endif
195 | }
196 |
--------------------------------------------------------------------------------
/NoxCap/inject-library.c:
--------------------------------------------------------------------------------
1 | #ifdef _MSC_VER
2 | #pragma warning(disable : 4152) /* casting func ptr to void */
3 | #endif
4 |
5 | #include
6 | #include
7 | #include "obfuscate.h"
8 | #include "inject-library.h"
9 |
10 | typedef HANDLE(WINAPI *create_remote_thread_t)(HANDLE, LPSECURITY_ATTRIBUTES,
11 | SIZE_T, LPTHREAD_START_ROUTINE,
12 | LPVOID, DWORD, LPDWORD);
13 | typedef BOOL(WINAPI *write_process_memory_t)(HANDLE, LPVOID, LPCVOID, SIZE_T,
14 | SIZE_T *);
15 | typedef LPVOID(WINAPI *virtual_alloc_ex_t)(HANDLE, LPVOID, SIZE_T, DWORD,
16 | DWORD);
17 | typedef BOOL(WINAPI *virtual_free_ex_t)(HANDLE, LPVOID, SIZE_T, DWORD);
18 |
19 | int inject_library_obf(HANDLE process, const wchar_t *dll,
20 | const char *create_remote_thread_obf, uint64_t obf1,
21 | const char *write_process_memory_obf, uint64_t obf2,
22 | const char *virtual_alloc_ex_obf, uint64_t obf3,
23 | const char *virtual_free_ex_obf, uint64_t obf4,
24 | const char *load_library_w_obf, uint64_t obf5)
25 | {
26 | int ret = INJECT_ERROR_UNLIKELY_FAIL;
27 | DWORD last_error = 0;
28 | bool success = false;
29 | size_t written_size;
30 | DWORD thread_id;
31 | HANDLE thread = NULL;
32 | size_t size;
33 | void *mem;
34 |
35 | /* -------------------------------- */
36 |
37 | HMODULE kernel32 = GetModuleHandleW(L"KERNEL32");
38 | create_remote_thread_t create_remote_thread;
39 | write_process_memory_t write_process_memory;
40 | virtual_alloc_ex_t virtual_alloc_ex;
41 | virtual_free_ex_t virtual_free_ex;
42 | FARPROC load_library_w;
43 |
44 | create_remote_thread =
45 | get_obfuscated_func(kernel32, create_remote_thread_obf, obf1);
46 | write_process_memory =
47 | get_obfuscated_func(kernel32, write_process_memory_obf, obf2);
48 | virtual_alloc_ex =
49 | get_obfuscated_func(kernel32, virtual_alloc_ex_obf, obf3);
50 | virtual_free_ex =
51 | get_obfuscated_func(kernel32, virtual_free_ex_obf, obf4);
52 | load_library_w =
53 | get_obfuscated_func(kernel32, load_library_w_obf, obf5);
54 |
55 | /* -------------------------------- */
56 |
57 | size = (wcslen(dll) + 1) * sizeof(wchar_t);
58 | mem = virtual_alloc_ex(process, NULL, size, MEM_RESERVE | MEM_COMMIT,
59 | PAGE_READWRITE);
60 | if (!mem) {
61 | goto fail;
62 | }
63 |
64 | success = write_process_memory(process, mem, dll, size, &written_size);
65 | if (!success) {
66 | goto fail;
67 | }
68 |
69 | thread = create_remote_thread(process, NULL, 0,
70 | (LPTHREAD_START_ROUTINE)load_library_w,
71 | mem, 0, &thread_id);
72 | if (!thread) {
73 | goto fail;
74 | }
75 |
76 | if (WaitForSingleObject(thread, 4000) == WAIT_OBJECT_0) {
77 | DWORD code;
78 | GetExitCodeThread(thread, &code);
79 | ret = (code != 0) ? 0 : INJECT_ERROR_INJECT_FAILED;
80 |
81 | SetLastError(0);
82 | }
83 |
84 | fail:
85 | if (ret == INJECT_ERROR_UNLIKELY_FAIL) {
86 | last_error = GetLastError();
87 | }
88 | if (thread) {
89 | CloseHandle(thread);
90 | }
91 | if (mem) {
92 | virtual_free_ex(process, mem, 0, MEM_RELEASE);
93 | }
94 | if (last_error != 0) {
95 | SetLastError(last_error);
96 | }
97 |
98 | return ret;
99 | }
100 |
101 | /* ------------------------------------------------------------------------- */
102 |
103 | typedef HHOOK(WINAPI *set_windows_hook_ex_t)(int, HOOKPROC, HINSTANCE, DWORD);
104 |
105 | #define RETRY_INTERVAL_MS 500
106 | #define TOTAL_RETRY_TIME_MS 4000
107 | #define RETRY_COUNT (TOTAL_RETRY_TIME_MS / RETRY_INTERVAL_MS)
108 |
109 | int inject_library_safe_obf(DWORD thread_id, const wchar_t *dll,
110 | const char *set_windows_hook_ex_obf, uint64_t obf1)
111 | {
112 | HMODULE user32 = GetModuleHandleW(L"USER32");
113 | set_windows_hook_ex_t set_windows_hook_ex;
114 | HMODULE lib = LoadLibraryW(dll);
115 | LPVOID proc;
116 | HHOOK hook;
117 | size_t i;
118 |
119 | if (!lib || !user32) {
120 | return INJECT_ERROR_UNLIKELY_FAIL;
121 | }
122 |
123 | #ifdef _WIN64
124 | proc = GetProcAddress(lib, "dummy_debug_proc");
125 | #else
126 | proc = GetProcAddress(lib, "_dummy_debug_proc@12");
127 | #endif
128 |
129 | if (!proc) {
130 | return INJECT_ERROR_UNLIKELY_FAIL;
131 | }
132 |
133 | set_windows_hook_ex =
134 | get_obfuscated_func(user32, set_windows_hook_ex_obf, obf1);
135 |
136 | hook = set_windows_hook_ex(WH_GETMESSAGE, proc, lib, thread_id);
137 | if (!hook) {
138 | return GetLastError();
139 | }
140 |
141 | /* SetWindowsHookEx does not inject the library in to the target
142 | * process unless the event associated with it has occurred, so
143 | * repeatedly send the hook message to start the hook at small
144 | * intervals to signal to SetWindowsHookEx to process the message and
145 | * therefore inject the library in to the target process. Repeating
146 | * this is mostly just a precaution. */
147 |
148 | for (i = 0; i < RETRY_COUNT; i++) {
149 | Sleep(RETRY_INTERVAL_MS);
150 | PostThreadMessage(thread_id, WM_USER + 432, 0, (LPARAM)hook);
151 | }
152 | return 0;
153 | }
154 |
--------------------------------------------------------------------------------
/NoxCap/semaphore.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Module: semaphore.h
3 | *
4 | * Purpose:
5 | * Semaphores aren't actually part of the PThreads standard.
6 | * They are defined by the POSIX Standard:
7 | *
8 | * POSIX 1003.1b-1993 (POSIX.1b)
9 | *
10 | * --------------------------------------------------------------------------
11 | *
12 | * Pthreads-win32 - POSIX Threads Library for Win32
13 | * Copyright(C) 1998 John E. Bossom
14 | * Copyright(C) 1999,2005 Pthreads-win32 contributors
15 | *
16 | * Contact Email: rpj@callisto.canberra.edu.au
17 | *
18 | * The current list of contributors is contained
19 | * in the file CONTRIBUTORS included with the source
20 | * code distribution. The list can also be seen at the
21 | * following World Wide Web location:
22 | * http://sources.redhat.com/pthreads-win32/contributors.html
23 | *
24 | * This library is free software; you can redistribute it and/or
25 | * modify it under the terms of the GNU Lesser General Public
26 | * License as published by the Free Software Foundation; either
27 | * version 2 of the License, or (at your option) any later version.
28 | *
29 | * This library is distributed in the hope that it will be useful,
30 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
32 | * Lesser General Public License for more details.
33 | *
34 | * You should have received a copy of the GNU Lesser General Public
35 | * License along with this library in the file COPYING.LIB;
36 | * if not, write to the Free Software Foundation, Inc.,
37 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
38 | */
39 | #if !defined( SEMAPHORE_H )
40 | #define SEMAPHORE_H
41 |
42 | #undef PTW32_SEMAPHORE_LEVEL
43 |
44 | #if defined(_POSIX_SOURCE)
45 | #define PTW32_SEMAPHORE_LEVEL 0
46 | /* Early POSIX */
47 | #endif
48 |
49 | #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
50 | #undef PTW32_SEMAPHORE_LEVEL
51 | #define PTW32_SEMAPHORE_LEVEL 1
52 | /* Include 1b, 1c and 1d */
53 | #endif
54 |
55 | #if defined(INCLUDE_NP)
56 | #undef PTW32_SEMAPHORE_LEVEL
57 | #define PTW32_SEMAPHORE_LEVEL 2
58 | /* Include Non-Portable extensions */
59 | #endif
60 |
61 | #define PTW32_SEMAPHORE_LEVEL_MAX 3
62 |
63 | #if !defined(PTW32_SEMAPHORE_LEVEL)
64 | #define PTW32_SEMAPHORE_LEVEL PTW32_SEMAPHORE_LEVEL_MAX
65 | /* Include everything */
66 | #endif
67 |
68 | #if defined(__GNUC__) && ! defined (__declspec)
69 | # error Please upgrade your GNU compiler to one that supports __declspec.
70 | #endif
71 |
72 | /*
73 | * When building the library, you should define PTW32_BUILD so that
74 | * the variables/functions are exported correctly. When using the library,
75 | * do NOT define PTW32_BUILD, and then the variables/functions will
76 | * be imported correctly.
77 | */
78 | #if !defined(PTW32_STATIC_LIB)
79 | # if defined(PTW32_BUILD)
80 | # define PTW32_DLLPORT __declspec (dllexport)
81 | # else
82 | # define PTW32_DLLPORT
83 | # endif
84 | #else
85 | # define PTW32_DLLPORT
86 | #endif
87 |
88 | /*
89 | * This is a duplicate of what is in the autoconf config.h,
90 | * which is only used when building the pthread-win32 libraries.
91 | */
92 |
93 | #if !defined(PTW32_CONFIG_H)
94 | # if defined(WINCE)
95 | # define NEED_ERRNO
96 | # define NEED_SEM
97 | # endif
98 | # if defined(__MINGW64__)
99 | # define HAVE_STRUCT_TIMESPEC
100 | # define HAVE_MODE_T
101 | # elif defined(_UWIN) || defined(__MINGW32__)
102 | # define HAVE_MODE_T
103 | # endif
104 | #endif
105 |
106 | /*
107 | *
108 | */
109 |
110 | #if PTW32_SEMAPHORE_LEVEL >= PTW32_SEMAPHORE_LEVEL_MAX
111 | #if defined(NEED_ERRNO)
112 | #include "need_errno.h"
113 | #else
114 | #include
115 | #endif
116 | #endif /* PTW32_SEMAPHORE_LEVEL >= PTW32_SEMAPHORE_LEVEL_MAX */
117 |
118 | #define _POSIX_SEMAPHORES
119 |
120 | #if defined(__cplusplus)
121 | extern "C"
122 | {
123 | #endif /* __cplusplus */
124 |
125 | #if !defined(HAVE_MODE_T)
126 | typedef unsigned int mode_t;
127 | #endif
128 |
129 |
130 | typedef struct sem_t_ * sem_t;
131 |
132 | PTW32_DLLPORT int __cdecl sem_init (sem_t * sem,
133 | int pshared,
134 | unsigned int value);
135 |
136 | PTW32_DLLPORT int __cdecl sem_destroy (sem_t * sem);
137 |
138 | PTW32_DLLPORT int __cdecl sem_trywait (sem_t * sem);
139 |
140 | PTW32_DLLPORT int __cdecl sem_wait (sem_t * sem);
141 |
142 | PTW32_DLLPORT int __cdecl sem_timedwait (sem_t * sem,
143 | const struct timespec * abstime);
144 |
145 | PTW32_DLLPORT int __cdecl sem_post (sem_t * sem);
146 |
147 | PTW32_DLLPORT int __cdecl sem_post_multiple (sem_t * sem,
148 | int count);
149 |
150 | PTW32_DLLPORT int __cdecl sem_open (const char * name,
151 | int oflag,
152 | mode_t mode,
153 | unsigned int value);
154 |
155 | PTW32_DLLPORT int __cdecl sem_close (sem_t * sem);
156 |
157 | PTW32_DLLPORT int __cdecl sem_unlink (const char * name);
158 |
159 | PTW32_DLLPORT int __cdecl sem_getvalue (sem_t * sem,
160 | int * sval);
161 |
162 | #if defined(__cplusplus)
163 | } /* End of extern "C" */
164 | #endif /* __cplusplus */
165 |
166 | #undef PTW32_SEMAPHORE_LEVEL
167 | #undef PTW32_SEMAPHORE_LEVEL_MAX
168 |
169 | #endif /* !SEMAPHORE_H */
170 |
--------------------------------------------------------------------------------
/Nox/libOpenGL/gl-helpers.c:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | Copyright (C) 2013 by Hugh Bailey
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 2 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | ******************************************************************************/
17 |
18 | #include "gl-subsystem.h"
19 |
20 | bool gl_init_face(GLenum target, GLenum type, uint32_t num_levels,
21 | GLenum format, GLint internal_format, bool compressed,
22 | uint32_t width, uint32_t height, uint32_t size,
23 | const uint8_t ***p_data)
24 | {
25 | bool success = true;
26 | const uint8_t **data = p_data ? *p_data : NULL;
27 | uint32_t i;
28 |
29 | for (i = 0; i < num_levels; i++) {
30 | if (compressed) {
31 | glCompressedTexImage2D(target, i, internal_format,
32 | width, height, 0, size,
33 | data ? *data : NULL);
34 | if (!gl_success("glCompressedTexImage2D"))
35 | success = false;
36 |
37 | } else {
38 | glTexImage2D(target, i, internal_format, width, height,
39 | 0, format, type, data ? *data : NULL);
40 | if (!gl_success("glTexImage2D"))
41 | success = false;
42 | }
43 |
44 | if (data)
45 | data++;
46 |
47 | size /= 4;
48 | width /= 2;
49 | height /= 2;
50 |
51 | if (width == 0)
52 | width = 1;
53 | if (height == 0)
54 | height = 1;
55 | }
56 |
57 | if (data)
58 | *p_data = data;
59 | return success;
60 | }
61 |
62 | static bool gl_copy_fbo(struct gs_texture *dst, uint32_t dst_x, uint32_t dst_y,
63 | struct gs_texture *src, uint32_t src_x, uint32_t src_y,
64 | uint32_t width, uint32_t height)
65 | {
66 | struct fbo_info *fbo = get_fbo(src, width, height);
67 | GLint last_fbo;
68 | bool success = false;
69 |
70 | if (!fbo)
71 | return false;
72 |
73 | if (!gl_get_integer_v(GL_READ_FRAMEBUFFER_BINDING, &last_fbo))
74 | return false;
75 | if (!gl_bind_framebuffer(GL_READ_FRAMEBUFFER, fbo->fbo))
76 | return false;
77 | if (!gl_bind_texture(dst->gl_target, dst->texture))
78 | goto fail;
79 |
80 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 0,
81 | src->gl_target, src->texture, 0);
82 | if (!gl_success("glFrameBufferTexture2D"))
83 | goto fail;
84 |
85 | glReadBuffer(GL_COLOR_ATTACHMENT0 + 0);
86 | if (!gl_success("glReadBuffer"))
87 | goto fail;
88 |
89 | glCopyTexSubImage2D(dst->gl_target, 0, dst_x, dst_y, src_x, src_y,
90 | width, height);
91 | if (!gl_success("glCopyTexSubImage2D"))
92 | goto fail;
93 |
94 | success = true;
95 |
96 | fail:
97 | if (!gl_bind_texture(dst->gl_target, 0))
98 | success = false;
99 | if (!gl_bind_framebuffer(GL_READ_FRAMEBUFFER, last_fbo))
100 | success = false;
101 |
102 | return success;
103 | }
104 |
105 | bool gl_copy_texture(struct gs_device *device, struct gs_texture *dst,
106 | uint32_t dst_x, uint32_t dst_y, struct gs_texture *src,
107 | uint32_t src_x, uint32_t src_y, uint32_t width,
108 | uint32_t height)
109 | {
110 | bool success = false;
111 |
112 | if (device->copy_type == COPY_TYPE_ARB) {
113 | glCopyImageSubData(src->texture, src->gl_target, 0, src_x,
114 | src_y, 0, dst->texture, dst->gl_target, 0,
115 | dst_x, dst_y, 0, width, height, 1);
116 | success = gl_success("glCopyImageSubData");
117 |
118 | } else if (device->copy_type == COPY_TYPE_NV) {
119 | glCopyImageSubDataNV(src->texture, src->gl_target, 0, src_x,
120 | src_y, 0, dst->texture, dst->gl_target, 0,
121 | dst_x, dst_y, 0, width, height, 1);
122 | success = gl_success("glCopyImageSubDataNV");
123 |
124 | } else if (device->copy_type == COPY_TYPE_FBO_BLIT) {
125 | success = gl_copy_fbo(dst, dst_x, dst_y, src, src_x, src_y,
126 | width, height);
127 | if (!success)
128 | blog(LOG_ERROR, "gl_copy_texture failed");
129 | }
130 |
131 | return success;
132 | }
133 |
134 | bool gl_create_buffer(GLenum target, GLuint *buffer, GLsizeiptr size,
135 | const GLvoid *data, GLenum usage)
136 | {
137 | bool success;
138 | if (!gl_gen_buffers(1, buffer))
139 | return false;
140 | if (!gl_bind_buffer(target, *buffer))
141 | return false;
142 |
143 | glBufferData(target, size, data, usage);
144 | success = gl_success("glBufferData");
145 |
146 | gl_bind_buffer(target, 0);
147 | return success;
148 | }
149 |
150 | bool update_buffer(GLenum target, GLuint buffer, const void *data, size_t size)
151 | {
152 | void *ptr;
153 | bool success = true;
154 |
155 | if (!gl_bind_buffer(target, buffer))
156 | return false;
157 |
158 | /* glMapBufferRange with these flags will actually give far better
159 | * performance than a plain glMapBuffer call */
160 | ptr = glMapBufferRange(target, 0, size,
161 | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
162 | success = gl_success("glMapBufferRange");
163 | if (success && ptr) {
164 | memcpy(ptr, data, size);
165 | glUnmapBuffer(target);
166 | }
167 |
168 | gl_bind_buffer(target, 0);
169 | return success;
170 | }
171 |
--------------------------------------------------------------------------------
/NoxCap/sched.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Module: sched.h
3 | *
4 | * Purpose:
5 | * Provides an implementation of POSIX realtime extensions
6 | * as defined in
7 | *
8 | * POSIX 1003.1b-1993 (POSIX.1b)
9 | *
10 | * --------------------------------------------------------------------------
11 | *
12 | * Pthreads-win32 - POSIX Threads Library for Win32
13 | * Copyright(C) 1998 John E. Bossom
14 | * Copyright(C) 1999,2005 Pthreads-win32 contributors
15 | *
16 | * Contact Email: rpj@callisto.canberra.edu.au
17 | *
18 | * The current list of contributors is contained
19 | * in the file CONTRIBUTORS included with the source
20 | * code distribution. The list can also be seen at the
21 | * following World Wide Web location:
22 | * http://sources.redhat.com/pthreads-win32/contributors.html
23 | *
24 | * This library is free software; you can redistribute it and/or
25 | * modify it under the terms of the GNU Lesser General Public
26 | * License as published by the Free Software Foundation; either
27 | * version 2 of the License, or (at your option) any later version.
28 | *
29 | * This library is distributed in the hope that it will be useful,
30 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
32 | * Lesser General Public License for more details.
33 | *
34 | * You should have received a copy of the GNU Lesser General Public
35 | * License along with this library in the file COPYING.LIB;
36 | * if not, write to the Free Software Foundation, Inc.,
37 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
38 | */
39 | #if !defined(_SCHED_H)
40 | #define _SCHED_H
41 |
42 | #undef PTW32_SCHED_LEVEL
43 |
44 | #if defined(_POSIX_SOURCE)
45 | #define PTW32_SCHED_LEVEL 0
46 | /* Early POSIX */
47 | #endif
48 |
49 | #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
50 | #undef PTW32_SCHED_LEVEL
51 | #define PTW32_SCHED_LEVEL 1
52 | /* Include 1b, 1c and 1d */
53 | #endif
54 |
55 | #if defined(INCLUDE_NP)
56 | #undef PTW32_SCHED_LEVEL
57 | #define PTW32_SCHED_LEVEL 2
58 | /* Include Non-Portable extensions */
59 | #endif
60 |
61 | #define PTW32_SCHED_LEVEL_MAX 3
62 |
63 | #if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_SCHED_LEVEL)
64 | #define PTW32_SCHED_LEVEL PTW32_SCHED_LEVEL_MAX
65 | /* Include everything */
66 | #endif
67 |
68 |
69 | #if defined(__GNUC__) && !defined(__declspec)
70 | # error Please upgrade your GNU compiler to one that supports __declspec.
71 | #endif
72 |
73 | /*
74 | * When building the library, you should define PTW32_BUILD so that
75 | * the variables/functions are exported correctly. When using the library,
76 | * do NOT define PTW32_BUILD, and then the variables/functions will
77 | * be imported correctly.
78 | */
79 | #if !defined(PTW32_STATIC_LIB)
80 | # if defined(PTW32_BUILD)
81 | # define PTW32_DLLPORT __declspec (dllexport)
82 | # else
83 | # define PTW32_DLLPORT
84 | # endif
85 | #else
86 | # define PTW32_DLLPORT
87 | #endif
88 |
89 | /*
90 | * This is a duplicate of what is in the autoconf config.h,
91 | * which is only used when building the pthread-win32 libraries.
92 | */
93 |
94 | #if !defined(PTW32_CONFIG_H)
95 | # if defined(WINCE)
96 | # define NEED_ERRNO
97 | # define NEED_SEM
98 | # endif
99 | # if defined(__MINGW64__)
100 | # define HAVE_STRUCT_TIMESPEC
101 | # define HAVE_MODE_T
102 | # elif defined(_UWIN) || defined(__MINGW32__)
103 | # define HAVE_MODE_T
104 | # endif
105 | #endif
106 |
107 | /*
108 | *
109 | */
110 |
111 | #if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX
112 | #if defined(NEED_ERRNO)
113 | #include "need_errno.h"
114 | #else
115 | #include
116 | #endif
117 | #endif /* PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX */
118 |
119 | #if (defined(__MINGW64__) || defined(__MINGW32__)) || defined(_UWIN)
120 | # if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX
121 | /* For pid_t */
122 | # include
123 | /* Required by Unix 98 */
124 | # include
125 | # else
126 | typedef int pid_t;
127 | # endif
128 | #else
129 | typedef int pid_t;
130 | #endif
131 |
132 | /* Thread scheduling policies */
133 |
134 | enum {
135 | SCHED_OTHER = 0,
136 | SCHED_FIFO,
137 | SCHED_RR,
138 | SCHED_MIN = SCHED_OTHER,
139 | SCHED_MAX = SCHED_RR
140 | };
141 |
142 | struct sched_param {
143 | int sched_priority;
144 | };
145 |
146 | #if defined(__cplusplus)
147 | extern "C"
148 | {
149 | #endif /* __cplusplus */
150 |
151 | PTW32_DLLPORT int __cdecl sched_yield (void);
152 |
153 | PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy);
154 |
155 | PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy);
156 |
157 | PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy);
158 |
159 | PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid);
160 |
161 | /*
162 | * Note that this macro returns ENOTSUP rather than
163 | * ENOSYS as might be expected. However, returning ENOSYS
164 | * should mean that sched_get_priority_{min,max} are
165 | * not implemented as well as sched_rr_get_interval.
166 | * This is not the case, since we just don't support
167 | * round-robin scheduling. Therefore I have chosen to
168 | * return the same value as sched_setscheduler when
169 | * SCHED_RR is passed to it.
170 | */
171 | #define sched_rr_get_interval(_pid, _interval) \
172 | ( errno = ENOTSUP, (int) -1 )
173 |
174 |
175 | #if defined(__cplusplus)
176 | } /* End of extern "C" */
177 | #endif /* __cplusplus */
178 |
179 | #undef PTW32_SCHED_LEVEL
180 | #undef PTW32_SCHED_LEVEL_MAX
181 |
182 | #endif /* !_SCHED_H */
183 |
184 |
--------------------------------------------------------------------------------
/Nox/Noxcap.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | //#include "graphics-hook-config.h"
4 |
5 | #ifdef _MSC_VER
6 | /* conversion from data/function pointer */
7 | #pragma warning(disable : 4152)
8 | #endif
9 |
10 | #include "graphics-hook-info.h"
11 | #include
12 |
13 | #ifdef __cplusplus
14 | extern "C" {
15 | #else
16 | #if defined(_MSC_VER) && !defined(inline)
17 | #define inline __inline
18 | #endif
19 | #endif
20 |
21 | #define NUM_BUFFERS 3
22 |
23 | extern void hlog(const char *format, ...);
24 | extern void hlog_hr(const char *text, HRESULT hr);
25 | static inline const char *get_process_name(void);
26 | static inline HMODULE get_system_module(const char *module);
27 | static inline HMODULE load_system_library(const char *module);
28 | extern uint64_t os_gettime_ns(void);
29 |
30 | static inline bool capture_active(void);
31 | static inline bool capture_ready(void);
32 | static inline bool capture_should_stop(void);
33 | static inline bool capture_should_init(void);
34 |
35 | extern void shmem_copy_data(size_t idx, void *volatile data);
36 | extern bool shmem_texture_data_lock(int idx);
37 | extern void shmem_texture_data_unlock(int idx);
38 |
39 | extern bool hook_ddraw(void);
40 | extern bool hook_d3d8(void);
41 | extern bool hook_d3d9(void);
42 | extern bool hook_dxgi(void);
43 | extern bool hook_gl(void);
44 |
45 | extern void d3d10_capture(void *swap, void *backbuffer, bool capture_overlay);
46 | extern void d3d10_free(void);
47 | extern void d3d11_capture(void *swap, void *backbuffer, bool capture_overlay);
48 | extern void d3d11_free(void);
49 |
50 | #if COMPILE_D3D12_HOOK
51 | extern void d3d12_capture(void *swap, void *backbuffer, bool capture_overlay);
52 | extern void d3d12_free(void);
53 | #endif
54 |
55 | extern uint8_t *get_d3d1x_vertex_shader(size_t *size);
56 | extern uint8_t *get_d3d1x_pixel_shader(size_t *size);
57 |
58 | extern bool rehook_gl(void);
59 |
60 | extern bool capture_init_shtex(struct shtex_data **data, HWND window,
61 | uint32_t base_cx, uint32_t base_cy, uint32_t cx,
62 | uint32_t cy, uint32_t format, bool flip,
63 | uintptr_t handle);
64 | extern bool capture_init_shmem(struct shmem_data **data, HWND window,
65 | uint32_t base_cx, uint32_t base_cy, uint32_t cx,
66 | uint32_t cy, uint32_t pitch, uint32_t format,
67 | bool flip);
68 | extern void capture_free(void);
69 |
70 | extern struct hook_info *global_hook_info;
71 |
72 | struct vertex {
73 | struct {
74 | float x, y, z, w;
75 | } pos;
76 | struct {
77 | float u, v;
78 | } tex;
79 | };
80 |
81 | static inline bool duplicate_handle(HANDLE *dst, HANDLE src)
82 | {
83 | return !!DuplicateHandle(GetCurrentProcess(), src, GetCurrentProcess(),
84 | dst, 0, false, DUPLICATE_SAME_ACCESS);
85 | }
86 |
87 | static inline void *get_offset_addr(HMODULE module, uint32_t offset)
88 | {
89 | return (void *)((uintptr_t)module + (uintptr_t)offset);
90 | }
91 |
92 | /* ------------------------------------------------------------------------- */
93 |
94 | extern HANDLE signal_restart;
95 | extern HANDLE signal_stop;
96 | extern HANDLE signal_ready;
97 | extern HANDLE signal_exit;
98 | extern HANDLE tex_mutexes[2];
99 | extern char system_path[MAX_PATH];
100 | extern char process_name[MAX_PATH];
101 | extern wchar_t keepalive_name[64];
102 | extern HWND dummy_window;
103 | extern volatile bool active;
104 |
105 | static inline const char *get_process_name(void)
106 | {
107 | return process_name;
108 | }
109 |
110 | static inline HMODULE get_system_module(const char *module)
111 | {
112 | char base_path[MAX_PATH];
113 |
114 | strcpy(base_path, system_path);
115 | strcat(base_path, "\\");
116 | strcat(base_path, module);
117 | return GetModuleHandleA(base_path);
118 | }
119 |
120 | static inline uint32_t module_size(HMODULE module)
121 | {
122 | MODULEINFO info;
123 | bool success = !!GetModuleInformation(GetCurrentProcess(), module,
124 | &info, sizeof(info));
125 | return success ? info.SizeOfImage : 0;
126 | }
127 |
128 | static inline HMODULE load_system_library(const char *name)
129 | {
130 | char base_path[MAX_PATH];
131 | HMODULE module;
132 |
133 | strcpy(base_path, system_path);
134 | strcat(base_path, "\\");
135 | strcat(base_path, name);
136 |
137 | module = GetModuleHandleA(base_path);
138 | if (module)
139 | return module;
140 |
141 | return LoadLibraryA(base_path);
142 | }
143 |
144 | static inline bool capture_alive(void)
145 | {
146 | HANDLE handle = OpenMutexW(SYNCHRONIZE, false, keepalive_name);
147 | CloseHandle(handle);
148 |
149 | if (handle)
150 | return true;
151 |
152 | return GetLastError() != ERROR_FILE_NOT_FOUND;
153 | }
154 |
155 | static inline bool capture_active(void)
156 | {
157 | return active;
158 | }
159 |
160 | static inline bool frame_ready(uint64_t interval)
161 | {
162 | static uint64_t last_time = 0;
163 | uint64_t elapsed;
164 | uint64_t t;
165 |
166 | if (!interval) {
167 | return true;
168 | }
169 |
170 | t = os_gettime_ns();
171 | elapsed = t - last_time;
172 |
173 | if (elapsed < interval) {
174 | return false;
175 | }
176 |
177 | last_time = (elapsed > interval * 2) ? t : last_time + interval;
178 | return true;
179 | }
180 |
181 | static inline bool capture_ready(void)
182 | {
183 | return capture_active() &&
184 | frame_ready(global_hook_info->frame_interval);
185 | }
186 |
187 | static inline bool capture_stopped(void)
188 | {
189 | return WaitForSingleObject(signal_stop, 0) == WAIT_OBJECT_0;
190 | }
191 |
192 | static inline bool capture_restarted(void)
193 | {
194 | return WaitForSingleObject(signal_restart, 0) == WAIT_OBJECT_0;
195 | }
196 |
197 | static inline bool capture_should_stop(void)
198 | {
199 | bool stop_requested = false;
200 |
201 | if (capture_active()) {
202 | static uint64_t last_keepalive_check = 0;
203 | uint64_t cur_time = os_gettime_ns();
204 | bool alive = true;
205 |
206 | if (cur_time - last_keepalive_check > 5000000000) {
207 | alive = capture_alive();
208 | last_keepalive_check = cur_time;
209 | }
210 |
211 | stop_requested = capture_stopped() || !alive;
212 | }
213 |
214 | return stop_requested;
215 | }
216 |
217 | extern bool init_pipe(void);
218 |
219 | static inline bool capture_should_init(void)
220 | {
221 | if (!capture_active() && capture_restarted()) {
222 | if (capture_alive()) {
223 | return true;
224 | }
225 | }
226 |
227 | return false;
228 | }
229 |
230 | #ifdef __cplusplus
231 | }
232 | #endif
233 |
--------------------------------------------------------------------------------
/Nox/graphic-hook/graphics-hook.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | //#include "graphics-hook-config.h"
4 |
5 | #ifdef _MSC_VER
6 | /* conversion from data/function pointer */
7 | #pragma warning(disable : 4152)
8 | #endif
9 |
10 | #include "../graphics-hook-info.h"
11 | #include
12 |
13 | #ifdef __cplusplus
14 | extern "C" {
15 | #else
16 | #if defined(_MSC_VER) && !defined(inline)
17 | #define inline __inline
18 | #endif
19 | #endif
20 |
21 | #define NUM_BUFFERS 3
22 |
23 | extern void hlog(const char *format, ...);
24 | extern void hlog_hr(const char *text, HRESULT hr);
25 | static inline const char *get_process_name(void);
26 | static inline HMODULE get_system_module(const char *module);
27 | static inline HMODULE load_system_library(const char *module);
28 | extern uint64_t os_gettime_ns(void);
29 |
30 | static inline bool capture_active(void);
31 | static inline bool capture_ready(void);
32 | static inline bool capture_should_stop(void);
33 | static inline bool capture_should_init(void);
34 |
35 | extern void shmem_copy_data(size_t idx, void *volatile data);
36 | extern bool shmem_texture_data_lock(int idx);
37 | extern void shmem_texture_data_unlock(int idx);
38 |
39 | extern bool hook_ddraw(void);
40 | extern bool hook_d3d8(void);
41 | extern bool hook_d3d9(void);
42 | extern bool hook_dxgi(void);
43 | extern bool hook_gl(void);
44 |
45 | extern void d3d10_capture(void *swap, void *backbuffer, bool capture_overlay);
46 | extern void d3d10_free(void);
47 | extern void d3d11_capture(void *swap, void *backbuffer, bool capture_overlay);
48 | extern void d3d11_free(void);
49 |
50 | #if COMPILE_D3D12_HOOK
51 | extern void d3d12_capture(void *swap, void *backbuffer, bool capture_overlay);
52 | extern void d3d12_free(void);
53 | #endif
54 |
55 | extern uint8_t *get_d3d1x_vertex_shader(size_t *size);
56 | extern uint8_t *get_d3d1x_pixel_shader(size_t *size);
57 |
58 | extern bool rehook_gl(void);
59 |
60 | extern bool capture_init_shtex(struct shtex_data **data, HWND window,
61 | uint32_t base_cx, uint32_t base_cy, uint32_t cx,
62 | uint32_t cy, uint32_t format, bool flip,
63 | uintptr_t handle);
64 | extern bool capture_init_shmem(struct shmem_data **data, HWND window,
65 | uint32_t base_cx, uint32_t base_cy, uint32_t cx,
66 | uint32_t cy, uint32_t pitch, uint32_t format,
67 | bool flip);
68 | extern void capture_free(void);
69 |
70 | extern struct hook_info *global_hook_info;
71 |
72 | struct vertex {
73 | struct {
74 | float x, y, z, w;
75 | } pos;
76 | struct {
77 | float u, v;
78 | } tex;
79 | };
80 |
81 | static inline bool duplicate_handle(HANDLE *dst, HANDLE src)
82 | {
83 | return !!DuplicateHandle(GetCurrentProcess(), src, GetCurrentProcess(),
84 | dst, 0, false, DUPLICATE_SAME_ACCESS);
85 | }
86 |
87 | static inline void *get_offset_addr(HMODULE module, uint32_t offset)
88 | {
89 | return (void *)((uintptr_t)module + (uintptr_t)offset);
90 | }
91 |
92 | /* ------------------------------------------------------------------------- */
93 |
94 | extern HANDLE signal_restart;
95 | extern HANDLE signal_stop;
96 | extern HANDLE signal_ready;
97 | extern HANDLE signal_exit;
98 | extern HANDLE tex_mutexes[2];
99 | extern char system_path[MAX_PATH];
100 | extern char process_name[MAX_PATH];
101 | extern wchar_t keepalive_name[64];
102 | extern HWND dummy_window;
103 | extern volatile bool active;
104 |
105 | static inline const char *get_process_name(void)
106 | {
107 | return process_name;
108 | }
109 |
110 | static inline HMODULE get_system_module(const char *module)
111 | {
112 | char base_path[MAX_PATH];
113 |
114 | strcpy(base_path, system_path);
115 | strcat(base_path, "\\");
116 | strcat(base_path, module);
117 | return GetModuleHandleA(base_path);
118 | }
119 |
120 | static inline uint32_t module_size(HMODULE module)
121 | {
122 | MODULEINFO info;
123 | bool success = !!GetModuleInformation(GetCurrentProcess(), module,
124 | &info, sizeof(info));
125 | return success ? info.SizeOfImage : 0;
126 | }
127 |
128 | static inline HMODULE load_system_library(const char *name)
129 | {
130 | char base_path[MAX_PATH];
131 | HMODULE module;
132 |
133 | strcpy(base_path, system_path);
134 | strcat(base_path, "\\");
135 | strcat(base_path, name);
136 |
137 | module = GetModuleHandleA(base_path);
138 | if (module)
139 | return module;
140 |
141 | return LoadLibraryA(base_path);
142 | }
143 |
144 | static inline bool capture_alive(void)
145 | {
146 | HANDLE handle = OpenMutexW(SYNCHRONIZE, false, keepalive_name);
147 | CloseHandle(handle);
148 |
149 | if (handle)
150 | return true;
151 |
152 | return GetLastError() != ERROR_FILE_NOT_FOUND;
153 | }
154 |
155 | static inline bool capture_active(void)
156 | {
157 | return active;
158 | }
159 |
160 | static inline bool frame_ready(uint64_t interval)
161 | {
162 | static uint64_t last_time = 0;
163 | uint64_t elapsed;
164 | uint64_t t;
165 |
166 | if (!interval) {
167 | return true;
168 | }
169 |
170 | t = os_gettime_ns();
171 | elapsed = t - last_time;
172 |
173 | if (elapsed < interval) {
174 | return false;
175 | }
176 |
177 | last_time = (elapsed > interval * 2) ? t : last_time + interval;
178 | return true;
179 | }
180 |
181 | static inline bool capture_ready(void)
182 | {
183 | return capture_active() &&
184 | frame_ready(global_hook_info->frame_interval);
185 | }
186 |
187 | static inline bool capture_stopped(void)
188 | {
189 | return WaitForSingleObject(signal_stop, 0) == WAIT_OBJECT_0;
190 | }
191 |
192 | static inline bool capture_restarted(void)
193 | {
194 | return WaitForSingleObject(signal_restart, 0) == WAIT_OBJECT_0;
195 | }
196 |
197 | static inline bool capture_should_stop(void)
198 | {
199 | bool stop_requested = false;
200 |
201 | if (capture_active()) {
202 | static uint64_t last_keepalive_check = 0;
203 | uint64_t cur_time = os_gettime_ns();
204 | bool alive = true;
205 |
206 | if (cur_time - last_keepalive_check > 5000000000) {
207 | alive = capture_alive();
208 | last_keepalive_check = cur_time;
209 | }
210 |
211 | stop_requested = capture_stopped() || !alive;
212 | }
213 |
214 | return stop_requested;
215 | }
216 |
217 | extern bool init_pipe(void);
218 |
219 | static inline bool capture_should_init(void)
220 | {
221 | if (!capture_active() && capture_restarted()) {
222 | if (capture_alive()) {
223 | return true;
224 | }
225 | }
226 |
227 | return false;
228 | }
229 |
230 | #ifdef __cplusplus
231 | }
232 | #endif
233 |
--------------------------------------------------------------------------------
/Nox/libOpenGL/gl-helpers.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | Copyright (C) 2013 by Hugh Bailey
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 2 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | ******************************************************************************/
17 |
18 | #pragma once
19 |
20 | static const char *gl_error_to_str(GLenum errorcode)
21 | {
22 | static const struct {
23 | GLenum error;
24 | const char *str;
25 | } err_to_str[] = {
26 | {
27 | GL_INVALID_ENUM,
28 | "GL_INVALID_ENUM",
29 | },
30 | {
31 | GL_INVALID_VALUE,
32 | "GL_INVALID_VALUE",
33 | },
34 | {
35 | GL_INVALID_OPERATION,
36 | "GL_INVALID_OPERATION",
37 | },
38 | {
39 | GL_INVALID_FRAMEBUFFER_OPERATION,
40 | "GL_INVALID_FRAMEBUFFER_OPERATION",
41 | },
42 | {
43 | GL_OUT_OF_MEMORY,
44 | "GL_OUT_OF_MEMORY",
45 | },
46 | {
47 | GL_STACK_UNDERFLOW,
48 | "GL_STACK_UNDERFLOW",
49 | },
50 | {
51 | GL_STACK_OVERFLOW,
52 | "GL_STACK_OVERFLOW",
53 | },
54 | };
55 | for (size_t i = 0; i < sizeof(err_to_str) / sizeof(*err_to_str); i++) {
56 | if (err_to_str[i].error == errorcode)
57 | return err_to_str[i].str;
58 | }
59 | return "Unknown";
60 | }
61 |
62 | /*
63 | * Okay, so GL error handling is.. unclean to work with. I don't want
64 | * to have to keep typing out the same stuff over and over again do I'll just
65 | * make a bunch of helper functions to make it a bit easier to handle errors
66 | */
67 |
68 | static inline bool gl_success(const char *funcname)
69 | {
70 | GLenum errorcode = glGetError();
71 | if (errorcode != GL_NO_ERROR) {
72 | int attempts = 8;
73 | do {
74 | blog(LOG_ERROR,
75 | "%s failed, glGetError returned %s(0x%X)",
76 | funcname, gl_error_to_str(errorcode), errorcode);
77 | errorcode = glGetError();
78 |
79 | --attempts;
80 | if (attempts == 0) {
81 | blog(LOG_ERROR,
82 | "Too many GL errors, moving on");
83 | break;
84 | }
85 | } while (errorcode != GL_NO_ERROR);
86 | return false;
87 | }
88 |
89 | return true;
90 | }
91 |
92 | static inline bool gl_gen_textures(GLsizei num_texture, GLuint *textures)
93 | {
94 | glGenTextures(num_texture, textures);
95 | return gl_success("glGenTextures");
96 | }
97 |
98 | static inline bool gl_bind_texture(GLenum target, GLuint texture)
99 | {
100 | glBindTexture(target, texture);
101 | return gl_success("glBindTexture");
102 | }
103 |
104 | static inline void gl_delete_textures(GLsizei num_buffers, GLuint *buffers)
105 | {
106 | glDeleteTextures(num_buffers, buffers);
107 | gl_success("glDeleteTextures");
108 | }
109 |
110 | static inline bool gl_gen_buffers(GLsizei num_buffers, GLuint *buffers)
111 | {
112 | glGenBuffers(num_buffers, buffers);
113 | return gl_success("glGenBuffers");
114 | }
115 |
116 | static inline bool gl_bind_buffer(GLenum target, GLuint buffer)
117 | {
118 | glBindBuffer(target, buffer);
119 | return gl_success("glBindBuffer");
120 | }
121 |
122 | static inline void gl_delete_buffers(GLsizei num_buffers, GLuint *buffers)
123 | {
124 | glDeleteBuffers(num_buffers, buffers);
125 | gl_success("glDeleteBuffers");
126 | }
127 |
128 | static inline bool gl_gen_vertex_arrays(GLsizei num_arrays, GLuint *arrays)
129 | {
130 | glGenVertexArrays(num_arrays, arrays);
131 | return gl_success("glGenVertexArrays");
132 | }
133 |
134 | static inline bool gl_bind_vertex_array(GLuint array)
135 | {
136 | glBindVertexArray(array);
137 | return gl_success("glBindVertexArray");
138 | }
139 |
140 | static inline void gl_delete_vertex_arrays(GLsizei num_arrays, GLuint *arrays)
141 | {
142 | glDeleteVertexArrays(num_arrays, arrays);
143 | gl_success("glDeleteVertexArrays");
144 | }
145 |
146 | static inline bool gl_bind_renderbuffer(GLenum target, GLuint buffer)
147 | {
148 | glBindRenderbuffer(target, buffer);
149 | return gl_success("glBindRendebuffer");
150 | }
151 |
152 | static inline bool gl_bind_framebuffer(GLenum target, GLuint buffer)
153 | {
154 | glBindFramebuffer(target, buffer);
155 | return gl_success("glBindFramebuffer");
156 | }
157 |
158 | static inline bool gl_tex_param_f(GLenum target, GLenum param, GLfloat val)
159 | {
160 | glTexParameterf(target, param, val);
161 | return gl_success("glTexParameterf");
162 | }
163 |
164 | static inline bool gl_tex_param_i(GLenum target, GLenum param, GLint val)
165 | {
166 | glTexParameteri(target, param, val);
167 | return gl_success("glTexParameteri");
168 | }
169 |
170 | static inline bool gl_active_texture(GLenum texture_id)
171 | {
172 | glActiveTexture(texture_id);
173 | return gl_success("glActiveTexture");
174 | }
175 |
176 | static inline bool gl_enable(GLenum capability)
177 | {
178 | glEnable(capability);
179 | return gl_success("glEnable");
180 | }
181 |
182 | static inline bool gl_disable(GLenum capability)
183 | {
184 | glDisable(capability);
185 | return gl_success("glDisable");
186 | }
187 |
188 | static inline bool gl_cull_face(GLenum faces)
189 | {
190 | glCullFace(faces);
191 | return gl_success("glCullFace");
192 | }
193 |
194 | static inline bool gl_get_integer_v(GLenum pname, GLint *params)
195 | {
196 | glGetIntegerv(pname, params);
197 | return gl_success("glGetIntegerv");
198 | }
199 |
200 | extern bool gl_init_face(GLenum target, GLenum type, uint32_t num_levels,
201 | GLenum format, GLint internal_format, bool compressed,
202 | uint32_t width, uint32_t height, uint32_t size,
203 | const uint8_t ***p_data);
204 |
205 | extern bool gl_copy_texture(struct gs_device *device, struct gs_texture *dst,
206 | uint32_t dst_x, uint32_t dst_y,
207 | struct gs_texture *src, uint32_t src_x,
208 | uint32_t src_y, uint32_t width, uint32_t height);
209 |
210 | extern bool gl_create_buffer(GLenum target, GLuint *buffer, GLsizeiptr size,
211 | const GLvoid *data, GLenum usage);
212 |
213 | extern bool update_buffer(GLenum target, GLuint buffer, const void *data,
214 | size_t size);
215 |
--------------------------------------------------------------------------------
/NoxCap/threading-posix.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Hugh Bailey
3 | *
4 | * Permission to use, copy, modify, and distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 |
17 | #if defined(__APPLE__) || defined(__MINGW32__)
18 | #include
19 | #endif
20 | #ifdef __APPLE__
21 | #include
22 | #include
23 | #include
24 | #else
25 | #define _GNU_SOURCE
26 | #include "semaphore.h"
27 | #endif
28 |
29 | #if defined(__FreeBSD__)
30 | #include
31 | #endif
32 |
33 | #include "bmem.h"
34 | #include "threading.h"
35 |
36 | struct os_event_data {
37 | pthread_mutex_t mutex;
38 | pthread_cond_t cond;
39 | volatile bool signalled;
40 | bool manual;
41 | };
42 |
43 | int os_event_init(os_event_t **event, enum os_event_type type)
44 | {
45 | int code = 0;
46 |
47 | struct os_event_data *data = bzalloc(sizeof(struct os_event_data));
48 |
49 | if ((code = pthread_mutex_init(&data->mutex, NULL)) < 0) {
50 | bfree(data);
51 | return code;
52 | }
53 |
54 | if ((code = pthread_cond_init(&data->cond, NULL)) < 0) {
55 | pthread_mutex_destroy(&data->mutex);
56 | bfree(data);
57 | return code;
58 | }
59 |
60 | data->manual = (type == OS_EVENT_TYPE_MANUAL);
61 | data->signalled = false;
62 | *event = data;
63 |
64 | return 0;
65 | }
66 |
67 | void os_event_destroy(os_event_t *event)
68 | {
69 | if (event) {
70 | pthread_mutex_destroy(&event->mutex);
71 | pthread_cond_destroy(&event->cond);
72 | bfree(event);
73 | }
74 | }
75 |
76 | int os_event_wait(os_event_t *event)
77 | {
78 | int code = 0;
79 | pthread_mutex_lock(&event->mutex);
80 | if (!event->signalled)
81 | code = pthread_cond_wait(&event->cond, &event->mutex);
82 |
83 | if (code == 0) {
84 | if (!event->manual)
85 | event->signalled = false;
86 | pthread_mutex_unlock(&event->mutex);
87 | }
88 |
89 | return code;
90 | }
91 |
92 | static inline void add_ms_to_ts(struct timespec *ts, unsigned long milliseconds)
93 | {
94 | ts->tv_sec += milliseconds / 1000;
95 | ts->tv_nsec += (milliseconds % 1000) * 1000000;
96 | if (ts->tv_nsec > 1000000000) {
97 | ts->tv_sec += 1;
98 | ts->tv_nsec -= 1000000000;
99 | }
100 | }
101 |
102 | int os_event_timedwait(os_event_t *event, unsigned long milliseconds)
103 | {
104 | int code = 0;
105 | pthread_mutex_lock(&event->mutex);
106 | if (!event->signalled) {
107 | struct timespec ts;
108 | #if defined(__APPLE__) || defined(__MINGW32__)
109 | struct timeval tv;
110 | gettimeofday(&tv, NULL);
111 | ts.tv_sec = tv.tv_sec;
112 | ts.tv_nsec = tv.tv_usec * 1000;
113 | #else
114 | clock_gettime(CLOCK_REALTIME, &ts);
115 | #endif
116 | add_ms_to_ts(&ts, milliseconds);
117 | code = pthread_cond_timedwait(&event->cond, &event->mutex, &ts);
118 | }
119 |
120 | if (code == 0) {
121 | if (!event->manual)
122 | event->signalled = false;
123 | }
124 |
125 | pthread_mutex_unlock(&event->mutex);
126 |
127 | return code;
128 | }
129 |
130 | int os_event_try(os_event_t *event)
131 | {
132 | int ret = EAGAIN;
133 |
134 | pthread_mutex_lock(&event->mutex);
135 | if (event->signalled) {
136 | if (!event->manual)
137 | event->signalled = false;
138 | ret = 0;
139 | }
140 | pthread_mutex_unlock(&event->mutex);
141 |
142 | return ret;
143 | }
144 |
145 | int os_event_signal(os_event_t *event)
146 | {
147 | int code = 0;
148 |
149 | pthread_mutex_lock(&event->mutex);
150 | code = pthread_cond_signal(&event->cond);
151 | event->signalled = true;
152 | pthread_mutex_unlock(&event->mutex);
153 |
154 | return code;
155 | }
156 |
157 | void os_event_reset(os_event_t *event)
158 | {
159 | pthread_mutex_lock(&event->mutex);
160 | event->signalled = false;
161 | pthread_mutex_unlock(&event->mutex);
162 | }
163 |
164 | #ifdef __APPLE__
165 |
166 | struct os_sem_data {
167 | semaphore_t sem;
168 | task_t task;
169 | };
170 |
171 | int os_sem_init(os_sem_t **sem, int value)
172 | {
173 | semaphore_t new_sem;
174 | task_t task = mach_task_self();
175 |
176 | if (semaphore_create(task, &new_sem, 0, value) != KERN_SUCCESS)
177 | return -1;
178 |
179 | *sem = bzalloc(sizeof(struct os_sem_data));
180 | if (!*sem)
181 | return -2;
182 |
183 | (*sem)->sem = new_sem;
184 | (*sem)->task = task;
185 | return 0;
186 | }
187 |
188 | void os_sem_destroy(os_sem_t *sem)
189 | {
190 | if (sem) {
191 | semaphore_destroy(sem->task, sem->sem);
192 | bfree(sem);
193 | }
194 | }
195 |
196 | int os_sem_post(os_sem_t *sem)
197 | {
198 | if (!sem)
199 | return -1;
200 | return (semaphore_signal(sem->sem) == KERN_SUCCESS) ? 0 : -1;
201 | }
202 |
203 | int os_sem_wait(os_sem_t *sem)
204 | {
205 | if (!sem)
206 | return -1;
207 | return (semaphore_wait(sem->sem) == KERN_SUCCESS) ? 0 : -1;
208 | }
209 |
210 | #else
211 |
212 | struct os_sem_data {
213 | sem_t sem;
214 | };
215 |
216 | int os_sem_init(os_sem_t **sem, int value)
217 | {
218 | sem_t new_sem;
219 | int ret = sem_init(&new_sem, 0, value);
220 | if (ret != 0)
221 | return ret;
222 |
223 | *sem = bzalloc(sizeof(struct os_sem_data));
224 | (*sem)->sem = new_sem;
225 | return 0;
226 | }
227 |
228 | void os_sem_destroy(os_sem_t *sem)
229 | {
230 | if (sem) {
231 | sem_destroy(&sem->sem);
232 | bfree(sem);
233 | }
234 | }
235 |
236 | int os_sem_post(os_sem_t *sem)
237 | {
238 | if (!sem)
239 | return -1;
240 | return sem_post(&sem->sem);
241 | }
242 |
243 | int os_sem_wait(os_sem_t *sem)
244 | {
245 | if (!sem)
246 | return -1;
247 | return sem_wait(&sem->sem);
248 | }
249 |
250 | #endif
251 |
252 | void os_set_thread_name(const char *name)
253 | {
254 | #if defined(__APPLE__)
255 | pthread_setname_np(name);
256 | #elif defined(__FreeBSD__)
257 | pthread_set_name_np(pthread_self(), name);
258 | #elif defined(__GLIBC__) && !defined(__MINGW32__)
259 | if (strlen(name) <= 15) {
260 | pthread_setname_np(pthread_self(), name);
261 | } else {
262 | char *thread_name = bstrdup_n(name, 15);
263 | pthread_setname_np(pthread_self(), thread_name);
264 | bfree(thread_name);
265 | }
266 | #endif
267 | }
268 |
--------------------------------------------------------------------------------
/NoxCap/nt-stuff.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #define THREAD_STATE_WAITING 5
6 | #define THREAD_WAIT_REASON_SUSPENDED 5
7 |
8 | typedef struct _OBS_SYSTEM_PROCESS_INFORMATION2 {
9 | ULONG NextEntryOffset;
10 | ULONG ThreadCount;
11 | BYTE Reserved1[48];
12 | PVOID Reserved2[3];
13 | HANDLE UniqueProcessId;
14 | PVOID Reserved3;
15 | ULONG HandleCount;
16 | BYTE Reserved4[4];
17 | PVOID Reserved5[11];
18 | SIZE_T PeakPagefileUsage;
19 | SIZE_T PrivatePageCount;
20 | LARGE_INTEGER Reserved6[6];
21 | } OBS_SYSTEM_PROCESS_INFORMATION2;
22 |
23 | typedef struct _OBS_SYSTEM_THREAD_INFORMATION {
24 | FILETIME KernelTime;
25 | FILETIME UserTime;
26 | FILETIME CreateTime;
27 | DWORD WaitTime;
28 | PVOID Address;
29 | HANDLE UniqueProcessId;
30 | HANDLE UniqueThreadId;
31 | DWORD Priority;
32 | DWORD BasePriority;
33 | DWORD ContextSwitches;
34 | DWORD ThreadState;
35 | DWORD WaitReason;
36 | DWORD Reserved1;
37 | } OBS_SYSTEM_THREAD_INFORMATION;
38 |
39 | #ifndef NT_SUCCESS
40 | #define NT_SUCCESS(status) ((NTSTATUS)(status) >= 0)
41 | #endif
42 |
43 | #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
44 |
45 | #define init_named_attribs(o, name) \
46 | do { \
47 | (o)->Length = sizeof(*(o)); \
48 | (o)->ObjectName = name; \
49 | (o)->RootDirectory = NULL; \
50 | (o)->Attributes = 0; \
51 | (o)->SecurityDescriptor = NULL; \
52 | (o)->SecurityQualityOfService = NULL; \
53 | } while (false)
54 |
55 | typedef void(WINAPI *RTLINITUNICODESTRINGFUNC)(PCUNICODE_STRING pstr,
56 | const wchar_t *lpstrName);
57 | typedef NTSTATUS(WINAPI *NTOPENFUNC)(PHANDLE phandle, ACCESS_MASK access,
58 | POBJECT_ATTRIBUTES objattr);
59 | typedef ULONG(WINAPI *RTLNTSTATUSTODOSERRORFUNC)(NTSTATUS status);
60 | typedef NTSTATUS(WINAPI *NTQUERYSYSTEMINFORMATIONFUNC)(SYSTEM_INFORMATION_CLASS,
61 | PVOID, ULONG, PULONG);
62 |
63 | static FARPROC get_nt_func(const char *name)
64 | {
65 | static bool initialized = false;
66 | static HANDLE ntdll = NULL;
67 | if (!initialized) {
68 | ntdll = GetModuleHandleW(L"ntdll");
69 | initialized = true;
70 | }
71 |
72 | return GetProcAddress(ntdll, name);
73 | }
74 |
75 | static void nt_set_last_error(NTSTATUS status)
76 | {
77 | static bool initialized = false;
78 | static RTLNTSTATUSTODOSERRORFUNC func = NULL;
79 |
80 | if (!initialized) {
81 | func = (RTLNTSTATUSTODOSERRORFUNC)get_nt_func(
82 | "RtlNtStatusToDosError");
83 | initialized = true;
84 | }
85 |
86 | if (func)
87 | SetLastError(func(status));
88 | }
89 |
90 | static void rtl_init_str(UNICODE_STRING *unistr, const wchar_t *str)
91 | {
92 | static bool initialized = false;
93 | static RTLINITUNICODESTRINGFUNC func = NULL;
94 |
95 | if (!initialized) {
96 | func = (RTLINITUNICODESTRINGFUNC)get_nt_func(
97 | "RtlInitUnicodeString");
98 | initialized = true;
99 | }
100 |
101 | if (func)
102 | func(unistr, str);
103 | }
104 |
105 | static NTSTATUS nt_query_information(SYSTEM_INFORMATION_CLASS info_class,
106 | PVOID info, ULONG info_len, PULONG ret_len)
107 | {
108 | static bool initialized = false;
109 | static NTQUERYSYSTEMINFORMATIONFUNC func = NULL;
110 |
111 | if (!initialized) {
112 | func = (NTQUERYSYSTEMINFORMATIONFUNC)get_nt_func(
113 | "NtQuerySystemInformation");
114 | initialized = true;
115 | }
116 |
117 | if (func)
118 | return func(info_class, info, info_len, ret_len);
119 | return (NTSTATUS)-1;
120 | }
121 |
122 | static bool thread_is_suspended(DWORD process_id, DWORD thread_id)
123 | {
124 | ULONG size = 4096;
125 | bool suspended = false;
126 | void *data = malloc(size);
127 |
128 | for (;;) {
129 | NTSTATUS stat = nt_query_information(SystemProcessInformation,
130 | data, size, &size);
131 | if (NT_SUCCESS(stat))
132 | break;
133 |
134 | if (stat != STATUS_INFO_LENGTH_MISMATCH) {
135 | goto fail;
136 | }
137 |
138 | free(data);
139 | size += 1024;
140 | data = malloc(size);
141 | }
142 |
143 | OBS_SYSTEM_PROCESS_INFORMATION2 *spi = data;
144 |
145 | for (;;) {
146 | if (spi->UniqueProcessId == (HANDLE)(DWORD_PTR)process_id) {
147 | break;
148 | }
149 |
150 | ULONG offset = spi->NextEntryOffset;
151 | if (!offset)
152 | goto fail;
153 |
154 | spi = (OBS_SYSTEM_PROCESS_INFORMATION2 *)((BYTE *)spi + offset);
155 | }
156 |
157 | OBS_SYSTEM_THREAD_INFORMATION *sti;
158 | OBS_SYSTEM_THREAD_INFORMATION *info = NULL;
159 | sti = (OBS_SYSTEM_THREAD_INFORMATION *)((BYTE *)spi + sizeof(*spi));
160 |
161 | for (ULONG i = 0; i < spi->ThreadCount; i++) {
162 | if (sti[i].UniqueThreadId == (HANDLE)(DWORD_PTR)thread_id) {
163 | info = &sti[i];
164 | break;
165 | }
166 | }
167 |
168 | if (info) {
169 | suspended = info->ThreadState == THREAD_STATE_WAITING &&
170 | info->WaitReason == THREAD_WAIT_REASON_SUSPENDED;
171 | }
172 |
173 | fail:
174 | free(data);
175 | return suspended;
176 | }
177 |
178 | #define MAKE_NT_OPEN_FUNC(func_name, nt_name, access) \
179 | static HANDLE func_name(const wchar_t *name) \
180 | { \
181 | static bool initialized = false; \
182 | static NTOPENFUNC open = NULL; \
183 | HANDLE handle; \
184 | NTSTATUS status; \
185 | UNICODE_STRING unistr; \
186 | OBJECT_ATTRIBUTES attr; \
187 | \
188 | if (!initialized) { \
189 | open = (NTOPENFUNC)get_nt_func(#nt_name); \
190 | initialized = true; \
191 | } \
192 | \
193 | if (!open) \
194 | return NULL; \
195 | \
196 | rtl_init_str(&unistr, name); \
197 | init_named_attribs(&attr, &unistr); \
198 | \
199 | status = open(&handle, access, &attr); \
200 | if (NT_SUCCESS(status)) \
201 | return handle; \
202 | nt_set_last_error(status); \
203 | return NULL; \
204 | }
205 |
206 | MAKE_NT_OPEN_FUNC(nt_open_mutex, NtOpenMutant, SYNCHRONIZE)
207 | MAKE_NT_OPEN_FUNC(nt_open_event, NtOpenEvent, EVENT_MODIFY_STATE | SYNCHRONIZE)
208 | MAKE_NT_OPEN_FUNC(nt_open_map, NtOpenSection, FILE_MAP_READ | FILE_MAP_WRITE)
209 |
--------------------------------------------------------------------------------
/Nox/graphic-hook/gl-decs.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | typedef unsigned int GLenum;
4 | typedef unsigned int GLbitfield;
5 | typedef unsigned int GLuint;
6 | typedef int GLint;
7 | typedef int GLsizei;
8 | typedef unsigned char GLboolean;
9 | typedef signed char GLbyte;
10 | typedef short GLshort;
11 | typedef unsigned char GLubyte;
12 | typedef unsigned short GLushort;
13 | typedef unsigned long GLulong;
14 | typedef float GLfloat;
15 | typedef float GLclampf;
16 | typedef double GLdouble;
17 | typedef double GLclampd;
18 | typedef void GLvoid;
19 | typedef ptrdiff_t GLintptrARB;
20 | typedef ptrdiff_t GLsizeiptrARB;
21 |
22 | #define GL_FRONT 0x0404
23 | #define GL_BACK 0x0405
24 |
25 | #define GL_INVALID_OPERATION 0x0502
26 |
27 | #define GL_UNSIGNED_BYTE 0x1401
28 |
29 | #define GL_RGB 0x1907
30 | #define GL_RGBA 0x1908
31 |
32 | #define GL_BGR 0x80E0
33 | #define GL_BGRA 0x80E1
34 |
35 | #define GL_NEAREST 0x2600
36 | #define GL_LINEAR 0x2601
37 |
38 | #define GL_READ_ONLY 0x88B8
39 | #define GL_WRITE_ONLY 0x88B9
40 | #define GL_READ_WRITE 0x88BA
41 | #define GL_BUFFER_ACCESS 0x88BB
42 | #define GL_BUFFER_MAPPED 0x88BC
43 | #define GL_BUFFER_MAP_POINTER 0x88BD
44 | #define GL_STREAM_DRAW 0x88E0
45 | #define GL_STREAM_READ 0x88E1
46 | #define GL_STREAM_COPY 0x88E2
47 | #define GL_STATIC_DRAW 0x88E4
48 | #define GL_STATIC_READ 0x88E5
49 | #define GL_STATIC_COPY 0x88E6
50 | #define GL_DYNAMIC_DRAW 0x88E8
51 | #define GL_DYNAMIC_READ 0x88E9
52 | #define GL_DYNAMIC_COPY 0x88EA
53 | #define GL_PIXEL_PACK_BUFFER 0x88EB
54 | #define GL_PIXEL_UNPACK_BUFFER 0x88EC
55 | #define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED
56 | #define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF
57 |
58 | #define GL_TEXTURE_2D 0x0DE1
59 | #define GL_TEXTURE_BINDING_2D 0x8069
60 | #define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6
61 |
62 | #define WGL_ACCESS_READ_ONLY_NV 0x0000
63 | #define WGL_ACCESS_READ_WRITE_NV 0x0001
64 | #define WGL_ACCESS_WRITE_DISCARD_NV 0x0002
65 |
66 | #define GL_READ_FRAMEBUFFER 0x8CA8
67 | #define GL_DRAW_FRAMEBUFFER 0x8CA9
68 | #define GL_COLOR_BUFFER_BIT 0x00004000
69 | #define GL_COLOR_ATTACHMENT0 0x8CE0
70 | #define GL_COLOR_ATTACHMENT1 0x8CE1
71 |
72 | typedef void(WINAPI *GLTEXIMAGE2DPROC)(GLenum target, GLint level,
73 | GLint internal_format, GLsizei width,
74 | GLsizei height, GLint border,
75 | GLenum format, GLenum type,
76 | const GLvoid *data);
77 | typedef void(WINAPI *GLGETTEXIMAGEPROC)(GLenum target, GLint level,
78 | GLenum format, GLenum type,
79 | GLvoid *img);
80 | typedef void(WINAPI *GLREADBUFFERPROC)(GLenum);
81 | typedef void(WINAPI *GLDRAWBUFFERPROC)(GLenum mode);
82 | typedef void(WINAPI *GLGETINTEGERVPROC)(GLenum pname, GLint *params);
83 | typedef GLenum(WINAPI *GLGETERRORPROC)();
84 | typedef BOOL(WINAPI *WGLSWAPLAYERBUFFERSPROC)(HDC, UINT);
85 | typedef BOOL(WINAPI *WGLSWAPBUFFERSPROC)(HDC);
86 | typedef BOOL(WINAPI *WGLDELETECONTEXTPROC)(HGLRC);
87 | typedef PROC(WINAPI *WGLGETPROCADDRESSPROC)(LPCSTR);
88 | typedef BOOL(WINAPI *WGLMAKECURRENTPROC)(HDC, HGLRC);
89 | typedef HDC(WINAPI *WGLGETCURRENTDCPROC)();
90 | typedef HGLRC(WINAPI *WGLGETCURRENTCONTEXTPROC)();
91 | typedef HGLRC(WINAPI *WGLCREATECONTEXTPROC)(HDC);
92 | typedef void(WINAPI *GLBUFFERDATAARBPROC)(GLenum target, GLsizeiptrARB size,
93 | const GLvoid *data, GLenum usage);
94 | typedef void(WINAPI *GLDELETEBUFFERSARBPROC)(GLsizei n, const GLuint *buffers);
95 | typedef void(WINAPI *GLDELETETEXTURESPROC)(GLsizei n, const GLuint *buffers);
96 | typedef void(WINAPI *GLGENBUFFERSARBPROC)(GLsizei n, GLuint *buffers);
97 | typedef void(WINAPI *GLGENTEXTURESPROC)(GLsizei n, GLuint *textures);
98 | typedef GLvoid *(WINAPI *GLMAPBUFFERPROC)(GLenum target, GLenum access);
99 | typedef GLboolean(WINAPI *GLUNMAPBUFFERPROC)(GLenum target);
100 | typedef void(WINAPI *GLBINDBUFFERPROC)(GLenum target, GLuint buffer);
101 | typedef void(WINAPI *GLBINDTEXTUREPROC)(GLenum target, GLuint texture);
102 | typedef void(WINAPI *GLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint *buffers);
103 | typedef void(WINAPI *GLDELETEFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers);
104 | typedef void(WINAPI *GLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer);
105 | typedef void(WINAPI *GLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0,
106 | GLint srcX1, GLint srcY1,
107 | GLint dstX0, GLint dstY0,
108 | GLint dstX1, GLint dstY1,
109 | GLbitfield mask, GLenum filter);
110 | typedef void(WINAPI *GLFRAMEBUFFERTEXTURE2DPROC)(GLenum target,
111 | GLenum attachment,
112 | GLenum textarget,
113 | GLuint texture, GLint level);
114 | typedef BOOL(WINAPI *WGLSETRESOURCESHAREHANDLENVPROC)(void *, HANDLE);
115 | typedef HANDLE(WINAPI *WGLDXOPENDEVICENVPROC)(void *);
116 | typedef BOOL(WINAPI *WGLDXCLOSEDEVICENVPROC)(HANDLE);
117 | typedef HANDLE(WINAPI *WGLDXREGISTEROBJECTNVPROC)(HANDLE, void *, GLuint,
118 | GLenum, GLenum);
119 | typedef BOOL(WINAPI *WGLDXUNREGISTEROBJECTNVPROC)(HANDLE, HANDLE);
120 | typedef BOOL(WINAPI *WGLDXOBJECTACCESSNVPROC)(HANDLE, GLenum);
121 | typedef BOOL(WINAPI *WGLDXLOCKOBJECTSNVPROC)(HANDLE, GLint, HANDLE *);
122 | typedef BOOL(WINAPI *WGLDXUNLOCKOBJECTSNVPROC)(HANDLE, GLint, HANDLE *);
123 |
124 |
125 |
126 | static GLTEXIMAGE2DPROC glTexImage2D = NULL;
127 | static GLGETTEXIMAGEPROC glGetTexImage = NULL;
128 | static GLREADBUFFERPROC glReadBuffer = NULL;
129 | static GLDRAWBUFFERPROC glDrawBuffer = NULL;
130 | static GLGETINTEGERVPROC glGetIntegerv = NULL;
131 | static GLGETERRORPROC glGetError = NULL;
132 | static WGLGETPROCADDRESSPROC jimglGetProcAddress = NULL;
133 | static WGLMAKECURRENTPROC jimglMakeCurrent = NULL;
134 | static WGLGETCURRENTDCPROC jimglGetCurrentDC = NULL;
135 | static WGLGETCURRENTCONTEXTPROC jimglGetCurrentContext = NULL;
136 | static GLBUFFERDATAARBPROC glBufferData = NULL;
137 | static GLDELETEBUFFERSARBPROC glDeleteBuffers = NULL;
138 | static GLDELETETEXTURESPROC glDeleteTextures = NULL;
139 | static GLGENBUFFERSARBPROC glGenBuffers = NULL;
140 | static GLGENTEXTURESPROC glGenTextures = NULL;
141 | static GLMAPBUFFERPROC glMapBuffer = NULL;
142 | static GLUNMAPBUFFERPROC glUnmapBuffer = NULL;
143 | static GLBINDBUFFERPROC glBindBuffer = NULL;
144 | static GLBINDTEXTUREPROC glBindTexture = NULL;
145 | static GLGENFRAMEBUFFERSPROC glGenFramebuffers = NULL;
146 | static GLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = NULL;
147 | static GLBINDFRAMEBUFFERPROC glBindFramebuffer = NULL;
148 | static GLBLITFRAMEBUFFERPROC glBlitFramebuffer = NULL;
149 | static GLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = NULL;
150 |
151 | static WGLSETRESOURCESHAREHANDLENVPROC jimglDXSetResourceShareHandleNV = NULL;
152 | static WGLDXOPENDEVICENVPROC jimglDXOpenDeviceNV = NULL;
153 | static WGLDXCLOSEDEVICENVPROC jimglDXCloseDeviceNV = NULL;
154 | static WGLDXREGISTEROBJECTNVPROC jimglDXRegisterObjectNV = NULL;
155 | static WGLDXUNREGISTEROBJECTNVPROC jimglDXUnregisterObjectNV = NULL;
156 | static WGLDXOBJECTACCESSNVPROC jimglDXObjectAccessNV = NULL;
157 | static WGLDXLOCKOBJECTSNVPROC jimglDXLockObjectsNV = NULL;
158 | static WGLDXUNLOCKOBJECTSNVPROC jimglDXUnlockObjectsNV = NULL;
159 |
160 |
--------------------------------------------------------------------------------
/Nox/graphic-hook/dxgi-capture.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include "d3d1x_shaders.hpp"
7 | #include "graphics-hook.h"
8 | #include "../funchook.h"
9 |
10 | #if COMPILE_D3D12_HOOK
11 | #include
12 | #endif
13 |
14 | typedef HRESULT(STDMETHODCALLTYPE *resize_buffers_t)(IDXGISwapChain *, UINT,
15 | UINT, UINT, DXGI_FORMAT,
16 | UINT);
17 | typedef HRESULT(STDMETHODCALLTYPE *present_t)(IDXGISwapChain *, UINT, UINT);
18 | typedef HRESULT(STDMETHODCALLTYPE *present1_t)(IDXGISwapChain1 *, UINT, UINT,
19 | const DXGI_PRESENT_PARAMETERS *);
20 |
21 | static struct func_hook resize_buffers;
22 | static struct func_hook present;
23 | static struct func_hook present1;
24 |
25 | static struct dxgi_swap_data data = {};
26 |
27 | static bool setup_dxgi(IDXGISwapChain *swap)
28 | {
29 | IUnknown *device;
30 | HRESULT hr;
31 |
32 | hr = swap->GetDevice(__uuidof(ID3D11Device), (void **)&device);
33 | if (SUCCEEDED(hr)) {
34 | ID3D11Device *d3d11 = reinterpret_cast(device);
35 | D3D_FEATURE_LEVEL level = d3d11->GetFeatureLevel();
36 | device->Release();
37 |
38 | if (level >= D3D_FEATURE_LEVEL_11_0) {
39 | data.swap = swap;
40 | data.capture = d3d11_capture;
41 | data.free = d3d11_free;
42 | return true;
43 | }
44 | }
45 |
46 | hr = swap->GetDevice(__uuidof(ID3D10Device), (void **)&device);
47 | if (SUCCEEDED(hr)) {
48 | data.swap = swap;
49 | data.capture = d3d10_capture;
50 | data.free = d3d10_free;
51 | device->Release();
52 | return true;
53 | }
54 |
55 | hr = swap->GetDevice(__uuidof(ID3D11Device), (void **)&device);
56 | if (SUCCEEDED(hr)) {
57 | data.swap = swap;
58 | data.capture = d3d11_capture;
59 | data.free = d3d11_free;
60 | device->Release();
61 | return true;
62 | }
63 |
64 | #if COMPILE_D3D12_HOOK
65 | hr = swap->GetDevice(__uuidof(ID3D12Device), (void **)&device);
66 | if (SUCCEEDED(hr)) {
67 | data.swap = swap;
68 | data.capture = d3d12_capture;
69 | data.free = d3d12_free;
70 | device->Release();
71 | return true;
72 | }
73 | #endif
74 |
75 | return false;
76 | }
77 |
78 | static bool resize_buffers_called = false;
79 |
80 | static HRESULT STDMETHODCALLTYPE hook_resize_buffers(IDXGISwapChain *swap,
81 | UINT buffer_count,
82 | UINT width, UINT height,
83 | DXGI_FORMAT format,
84 | UINT flags)
85 | {
86 | HRESULT hr;
87 |
88 | if (!!data.free)
89 | data.free();
90 |
91 | data.swap = nullptr;
92 | data.free = nullptr;
93 | data.capture = nullptr;
94 |
95 | unhook(&resize_buffers);
96 | resize_buffers_t call = (resize_buffers_t)resize_buffers.call_addr;
97 | hr = call(swap, buffer_count, width, height, format, flags);
98 | rehook(&resize_buffers);
99 |
100 | resize_buffers_called = true;
101 |
102 | return hr;
103 | }
104 |
105 | static inline IUnknown *get_dxgi_backbuffer(IDXGISwapChain *swap)
106 | {
107 | IDXGIResource *res = nullptr;
108 | HRESULT hr;
109 |
110 | hr = swap->GetBuffer(0, __uuidof(IUnknown), (void **)&res);
111 | if (FAILED(hr))
112 | hlog_hr("get_dxgi_backbuffer: GetBuffer failed", hr);
113 |
114 | return res;
115 | }
116 |
117 | static HRESULT STDMETHODCALLTYPE hook_present(IDXGISwapChain *swap,
118 | UINT sync_interval, UINT flags)
119 | {
120 | IUnknown *backbuffer = nullptr;
121 | bool capture_overlay = global_hook_info->capture_overlay;
122 | bool test_draw = (flags & DXGI_PRESENT_TEST) != 0;
123 | bool capture;
124 | HRESULT hr;
125 |
126 | if (!data.swap && !capture_active()) {
127 | setup_dxgi(swap);
128 | }
129 |
130 | capture = !test_draw && swap == data.swap && !!data.capture;
131 | if (capture && !capture_overlay) {
132 | backbuffer = get_dxgi_backbuffer(swap);
133 |
134 | if (!!backbuffer) {
135 | data.capture(swap, backbuffer, capture_overlay);
136 | backbuffer->Release();
137 | }
138 | }
139 |
140 | unhook(&present);
141 | present_t call = (present_t)present.call_addr;
142 | hr = call(swap, sync_interval, flags);
143 | rehook(&present);
144 |
145 | if (capture && capture_overlay) {
146 | /*
147 | * It seems that the first call to Present after ResizeBuffers
148 | * will cause the backbuffer to be invalidated, so do not
149 | * perform the post-overlay capture if ResizeBuffers has
150 | * recently been called. (The backbuffer returned by
151 | * get_dxgi_backbuffer *will* be invalid otherwise)
152 | */
153 | if (resize_buffers_called) {
154 | resize_buffers_called = false;
155 | } else {
156 | backbuffer = get_dxgi_backbuffer(swap);
157 |
158 | if (!!backbuffer) {
159 | data.capture(swap, backbuffer, capture_overlay);
160 | backbuffer->Release();
161 | }
162 | }
163 | }
164 |
165 | return hr;
166 | }
167 |
168 | static HRESULT STDMETHODCALLTYPE
169 | hook_present1(IDXGISwapChain1 *swap, UINT sync_interval, UINT flags,
170 | const DXGI_PRESENT_PARAMETERS *params)
171 | {
172 | IUnknown *backbuffer = nullptr;
173 | bool capture_overlay = global_hook_info->capture_overlay;
174 | bool test_draw = (flags & DXGI_PRESENT_TEST) != 0;
175 | bool capture;
176 | HRESULT hr;
177 |
178 | if (!data.swap && !capture_active()) {
179 | setup_dxgi(swap);
180 | }
181 |
182 | capture = !test_draw && swap == data.swap && !!data.capture;
183 | if (capture && !capture_overlay) {
184 | backbuffer = get_dxgi_backbuffer(swap);
185 |
186 | if (!!backbuffer) {
187 | DXGI_SWAP_CHAIN_DESC1 desc;
188 | swap->GetDesc1(&desc);
189 | data.capture(swap, backbuffer, capture_overlay);
190 | backbuffer->Release();
191 | }
192 | }
193 |
194 | unhook(&present1);
195 | present1_t call = (present1_t)present1.call_addr;
196 | hr = call(swap, sync_interval, flags, params);
197 | rehook(&present1);
198 |
199 | if (capture && capture_overlay) {
200 | if (resize_buffers_called) {
201 | resize_buffers_called = false;
202 | } else {
203 | backbuffer = get_dxgi_backbuffer(swap);
204 |
205 | if (!!backbuffer) {
206 | data.capture(swap, backbuffer, capture_overlay);
207 | backbuffer->Release();
208 | }
209 | }
210 | }
211 |
212 | return hr;
213 | }
214 |
215 | static pD3DCompile get_compiler(void)
216 | {
217 | pD3DCompile compile = nullptr;
218 | char d3dcompiler[40] = {};
219 | int ver = 49;
220 |
221 | while (ver > 30) {
222 | sprintf_s(d3dcompiler, 40, "D3DCompiler_%02d.dll", ver);
223 |
224 | HMODULE module = LoadLibraryA(d3dcompiler);
225 | if (module) {
226 | compile = (pD3DCompile)GetProcAddress(module,
227 | "D3DCompile");
228 | if (compile) {
229 | break;
230 | }
231 | }
232 |
233 | ver--;
234 | }
235 |
236 | return compile;
237 | }
238 |
239 | static uint8_t vertex_shader_data[1024];
240 | static uint8_t pixel_shader_data[1024];
241 | static size_t vertex_shader_size = 0;
242 | static size_t pixel_shader_size = 0;
243 |
244 | uint8_t *get_d3d1x_vertex_shader(size_t *size)
245 | {
246 | *size = vertex_shader_size;
247 | return vertex_shader_data;
248 | }
249 |
250 | uint8_t *get_d3d1x_pixel_shader(size_t *size)
251 | {
252 | *size = pixel_shader_size;
253 | return pixel_shader_data;
254 | }
255 |
--------------------------------------------------------------------------------
/Nox/libOpenGL/gl-stagesurf.c:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | Copyright (C) 2013 by Hugh Bailey
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 2 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | ******************************************************************************/
17 |
18 | #include "gl-subsystem.h"
19 |
20 | static bool create_pixel_pack_buffer(struct gs_stage_surface *surf)
21 | {
22 | GLsizeiptr size;
23 | bool success = true;
24 |
25 | if (!gl_gen_buffers(1, &surf->pack_buffer))
26 | return false;
27 |
28 | if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, surf->pack_buffer))
29 | return false;
30 |
31 | size = surf->width * surf->bytes_per_pixel;
32 | size = (size + 3) & 0xFFFFFFFC; /* align width to 4-byte boundary */
33 | size *= surf->height;
34 |
35 | glBufferData(GL_PIXEL_PACK_BUFFER, size, 0, GL_DYNAMIC_READ);
36 | if (!gl_success("glBufferData"))
37 | success = false;
38 |
39 | if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0))
40 | success = false;
41 |
42 | return success;
43 | }
44 |
45 | gs_stagesurf_t *device_stagesurface_create(gs_device_t *device, uint32_t width,
46 | uint32_t height,
47 | enum gs_color_format color_format)
48 | {
49 | struct gs_stage_surface *surf;
50 | surf = bzalloc(sizeof(struct gs_stage_surface));
51 | surf->device = device;
52 | surf->format = color_format;
53 | surf->width = width;
54 | surf->height = height;
55 | surf->gl_format = convert_gs_format(color_format);
56 | surf->gl_internal_format = convert_gs_internal_format(color_format);
57 | surf->gl_type = get_gl_format_type(color_format);
58 | surf->bytes_per_pixel = gs_get_format_bpp(color_format) / 8;
59 |
60 | if (!create_pixel_pack_buffer(surf)) {
61 | blog(LOG_ERROR, "device_stagesurface_create (GL) failed");
62 | gs_stagesurface_destroy(surf);
63 | return NULL;
64 | }
65 |
66 | return surf;
67 | }
68 |
69 | void gs_stagesurface_destroy(gs_stagesurf_t *stagesurf)
70 | {
71 | if (stagesurf) {
72 | if (stagesurf->pack_buffer)
73 | gl_delete_buffers(1, &stagesurf->pack_buffer);
74 |
75 | bfree(stagesurf);
76 | }
77 | }
78 |
79 | static bool can_stage(struct gs_stage_surface *dst, struct gs_texture_2d *src)
80 | {
81 | if (!src) {
82 | blog(LOG_ERROR, "Source texture is NULL");
83 | return false;
84 | }
85 |
86 | if (src->base.type != GS_TEXTURE_2D) {
87 | blog(LOG_ERROR, "Source texture must be a 2D texture");
88 | return false;
89 | }
90 |
91 | if (!dst) {
92 | blog(LOG_ERROR, "Destination surface is NULL");
93 | return false;
94 | }
95 |
96 | if (src->base.format != dst->format) {
97 | blog(LOG_ERROR, "Source and destination formats do not match");
98 | return false;
99 | }
100 |
101 | if (src->width != dst->width || src->height != dst->height) {
102 | blog(LOG_ERROR, "Source and destination must have the same "
103 | "dimensions");
104 | return false;
105 | }
106 |
107 | return true;
108 | }
109 |
110 | #ifdef __APPLE__
111 |
112 | /* Apparently for mac, PBOs won't do an asynchronous transfer unless you use
113 | * FBOs along with glReadPixels, which is really dumb. */
114 | void device_stage_texture(gs_device_t *device, gs_stagesurf_t *dst,
115 | gs_texture_t *src)
116 | {
117 | struct gs_texture_2d *tex2d = (struct gs_texture_2d *)src;
118 | struct fbo_info *fbo;
119 | GLint last_fbo;
120 | bool success = false;
121 |
122 | if (!can_stage(dst, tex2d))
123 | goto failed;
124 |
125 | if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, dst->pack_buffer))
126 | goto failed;
127 |
128 | fbo = get_fbo(src, dst->width, dst->height);
129 |
130 | if (!gl_get_integer_v(GL_READ_FRAMEBUFFER_BINDING, &last_fbo))
131 | goto failed_unbind_buffer;
132 | if (!gl_bind_framebuffer(GL_READ_FRAMEBUFFER, fbo->fbo))
133 | goto failed_unbind_buffer;
134 |
135 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 0,
136 | src->gl_target, src->texture, 0);
137 | if (!gl_success("glFrameBufferTexture2D"))
138 | goto failed_unbind_all;
139 |
140 | glReadPixels(0, 0, dst->width, dst->height, dst->gl_format,
141 | dst->gl_type, 0);
142 | if (!gl_success("glReadPixels"))
143 | goto failed_unbind_all;
144 |
145 | success = true;
146 |
147 | failed_unbind_all:
148 | gl_bind_framebuffer(GL_READ_FRAMEBUFFER, last_fbo);
149 |
150 | failed_unbind_buffer:
151 | gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0);
152 |
153 | failed:
154 | if (!success)
155 | blog(LOG_ERROR, "device_stage_texture (GL) failed");
156 |
157 | UNUSED_PARAMETER(device);
158 | }
159 |
160 | #else
161 |
162 | void device_stage_texture(gs_device_t *device, gs_stagesurf_t *dst,
163 | gs_texture_t *src)
164 | {
165 | struct gs_texture_2d *tex2d = (struct gs_texture_2d *)src;
166 | if (!can_stage(dst, tex2d))
167 | goto failed;
168 |
169 | if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, dst->pack_buffer))
170 | goto failed;
171 | if (!gl_bind_texture(GL_TEXTURE_2D, tex2d->base.texture))
172 | goto failed;
173 |
174 | glGetTexImage(GL_TEXTURE_2D, 0, dst->gl_format, dst->gl_type, 0);
175 | if (!gl_success("glGetTexImage"))
176 | goto failed;
177 |
178 | gl_bind_texture(GL_TEXTURE_2D, 0);
179 | gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0);
180 | return;
181 |
182 | failed:
183 | gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0);
184 | gl_bind_texture(GL_TEXTURE_2D, 0);
185 | blog(LOG_ERROR, "device_stage_texture (GL) failed");
186 |
187 | UNUSED_PARAMETER(device);
188 | }
189 |
190 | #endif
191 |
192 | uint32_t gs_stagesurface_get_width(const gs_stagesurf_t *stagesurf)
193 | {
194 | return stagesurf->width;
195 | }
196 |
197 | uint32_t gs_stagesurface_get_height(const gs_stagesurf_t *stagesurf)
198 | {
199 | return stagesurf->height;
200 | }
201 |
202 | enum gs_color_format
203 | gs_stagesurface_get_color_format(const gs_stagesurf_t *stagesurf)
204 | {
205 | return stagesurf->format;
206 | }
207 |
208 | bool gs_stagesurface_map(gs_stagesurf_t *stagesurf, uint8_t **data,
209 | uint32_t *linesize)
210 | {
211 | if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, stagesurf->pack_buffer))
212 | goto fail;
213 |
214 | *data = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
215 | if (!gl_success("glMapBuffer"))
216 | goto fail;
217 |
218 | gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0);
219 |
220 | *linesize = stagesurf->bytes_per_pixel * stagesurf->width;
221 | return true;
222 |
223 | fail:
224 | blog(LOG_ERROR, "stagesurf_map (GL) failed");
225 | return false;
226 | }
227 |
228 | void gs_stagesurface_unmap(gs_stagesurf_t *stagesurf)
229 | {
230 | if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, stagesurf->pack_buffer))
231 | return;
232 |
233 | glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
234 | gl_success("glUnmapBuffer");
235 |
236 | gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0);
237 | }
238 |
--------------------------------------------------------------------------------
/NoxCap/graphics-hook-info.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include "hook-helpers.h"
9 |
10 | #define EVENT_CAPTURE_RESTART L"CaptureHook_Restart"
11 | #define EVENT_CAPTURE_STOP L"CaptureHook_Stop"
12 |
13 | #define EVENT_HOOK_READY L"CaptureHook_HookReady"
14 | #define EVENT_HOOK_EXIT L"CaptureHook_Exit"
15 |
16 | #define EVENT_HOOK_INIT L"CaptureHook_Initialize"
17 |
18 | #define WINDOW_HOOK_KEEPALIVE L"CaptureHook_KeepAlive"
19 |
20 | #define MUTEX_TEXTURE1 L"CaptureHook_TextureMutex1"
21 | #define MUTEX_TEXTURE2 L"CaptureHook_TextureMutex2"
22 |
23 | #define SHMEM_HOOK_INFO L"CaptureHook_HookInfo"
24 | #define SHMEM_TEXTURE L"CaptureHook_Texture"
25 |
26 | #define PIPE_NAME "CaptureHook_Pipe"
27 |
28 | #pragma pack(push, 8)
29 |
30 | struct d3d8_offsets {
31 | uint32_t present;
32 | };
33 |
34 | struct d3d9_offsets {
35 | uint32_t present;
36 | uint32_t present_ex;
37 | uint32_t present_swap;
38 | uint32_t d3d9_clsoff;
39 | uint32_t is_d3d9ex_clsoff;
40 | };
41 |
42 | struct dxgi_offsets {
43 | uint32_t present;
44 | uint32_t resize;
45 |
46 | uint32_t present1;
47 | };
48 |
49 | struct ddraw_offsets {
50 | uint32_t surface_create;
51 | uint32_t surface_restore;
52 | uint32_t surface_release;
53 | uint32_t surface_unlock;
54 | uint32_t surface_blt;
55 | uint32_t surface_flip;
56 | uint32_t surface_set_palette;
57 | uint32_t palette_set_entries;
58 | };
59 |
60 | struct shmem_data {
61 | volatile int last_tex;
62 | uint32_t tex1_offset;
63 | uint32_t tex2_offset;
64 | };
65 |
66 | struct shtex_data {
67 | uint32_t tex_handle;
68 | };
69 |
70 | enum capture_type {
71 | CAPTURE_TYPE_MEMORY,
72 | CAPTURE_TYPE_TEXTURE,
73 | };
74 |
75 | struct graphics_offsets {
76 | struct d3d8_offsets d3d8;
77 | struct d3d9_offsets d3d9;
78 | struct dxgi_offsets dxgi;
79 | struct ddraw_offsets ddraw;
80 | };
81 |
82 | struct hook_info {
83 | /* capture info */
84 | enum capture_type type;
85 | uint32_t window;
86 | uint32_t format;
87 | uint32_t cx;
88 | uint32_t cy;
89 | uint32_t base_cx;
90 | uint32_t base_cy;
91 | uint32_t pitch;
92 | uint32_t map_id;
93 | uint32_t map_size;
94 | bool flip;
95 |
96 | /* additional options */
97 | uint64_t frame_interval;
98 | bool use_scale;
99 | bool force_shmem;
100 | bool capture_overlay;
101 |
102 | /* hook addresses */
103 | struct graphics_offsets offsets;
104 | };
105 |
106 | typedef enum DXGI_FORMAT
107 | {
108 | DXGI_FORMAT_UNKNOWN = 0,
109 | DXGI_FORMAT_R32G32B32A32_TYPELESS = 1,
110 | DXGI_FORMAT_R32G32B32A32_FLOAT = 2,
111 | DXGI_FORMAT_R32G32B32A32_UINT = 3,
112 | DXGI_FORMAT_R32G32B32A32_SINT = 4,
113 | DXGI_FORMAT_R32G32B32_TYPELESS = 5,
114 | DXGI_FORMAT_R32G32B32_FLOAT = 6,
115 | DXGI_FORMAT_R32G32B32_UINT = 7,
116 | DXGI_FORMAT_R32G32B32_SINT = 8,
117 | DXGI_FORMAT_R16G16B16A16_TYPELESS = 9,
118 | DXGI_FORMAT_R16G16B16A16_FLOAT = 10,
119 | DXGI_FORMAT_R16G16B16A16_UNORM = 11,
120 | DXGI_FORMAT_R16G16B16A16_UINT = 12,
121 | DXGI_FORMAT_R16G16B16A16_SNORM = 13,
122 | DXGI_FORMAT_R16G16B16A16_SINT = 14,
123 | DXGI_FORMAT_R32G32_TYPELESS = 15,
124 | DXGI_FORMAT_R32G32_FLOAT = 16,
125 | DXGI_FORMAT_R32G32_UINT = 17,
126 | DXGI_FORMAT_R32G32_SINT = 18,
127 | DXGI_FORMAT_R32G8X24_TYPELESS = 19,
128 | DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20,
129 | DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21,
130 | DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22,
131 | DXGI_FORMAT_R10G10B10A2_TYPELESS = 23,
132 | DXGI_FORMAT_R10G10B10A2_UNORM = 24,
133 | DXGI_FORMAT_R10G10B10A2_UINT = 25,
134 | DXGI_FORMAT_R11G11B10_FLOAT = 26,
135 | DXGI_FORMAT_R8G8B8A8_TYPELESS = 27,
136 | DXGI_FORMAT_R8G8B8A8_UNORM = 28,
137 | DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29,
138 | DXGI_FORMAT_R8G8B8A8_UINT = 30,
139 | DXGI_FORMAT_R8G8B8A8_SNORM = 31,
140 | DXGI_FORMAT_R8G8B8A8_SINT = 32,
141 | DXGI_FORMAT_R16G16_TYPELESS = 33,
142 | DXGI_FORMAT_R16G16_FLOAT = 34,
143 | DXGI_FORMAT_R16G16_UNORM = 35,
144 | DXGI_FORMAT_R16G16_UINT = 36,
145 | DXGI_FORMAT_R16G16_SNORM = 37,
146 | DXGI_FORMAT_R16G16_SINT = 38,
147 | DXGI_FORMAT_R32_TYPELESS = 39,
148 | DXGI_FORMAT_D32_FLOAT = 40,
149 | DXGI_FORMAT_R32_FLOAT = 41,
150 | DXGI_FORMAT_R32_UINT = 42,
151 | DXGI_FORMAT_R32_SINT = 43,
152 | DXGI_FORMAT_R24G8_TYPELESS = 44,
153 | DXGI_FORMAT_D24_UNORM_S8_UINT = 45,
154 | DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46,
155 | DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47,
156 | DXGI_FORMAT_R8G8_TYPELESS = 48,
157 | DXGI_FORMAT_R8G8_UNORM = 49,
158 | DXGI_FORMAT_R8G8_UINT = 50,
159 | DXGI_FORMAT_R8G8_SNORM = 51,
160 | DXGI_FORMAT_R8G8_SINT = 52,
161 | DXGI_FORMAT_R16_TYPELESS = 53,
162 | DXGI_FORMAT_R16_FLOAT = 54,
163 | DXGI_FORMAT_D16_UNORM = 55,
164 | DXGI_FORMAT_R16_UNORM = 56,
165 | DXGI_FORMAT_R16_UINT = 57,
166 | DXGI_FORMAT_R16_SNORM = 58,
167 | DXGI_FORMAT_R16_SINT = 59,
168 | DXGI_FORMAT_R8_TYPELESS = 60,
169 | DXGI_FORMAT_R8_UNORM = 61,
170 | DXGI_FORMAT_R8_UINT = 62,
171 | DXGI_FORMAT_R8_SNORM = 63,
172 | DXGI_FORMAT_R8_SINT = 64,
173 | DXGI_FORMAT_A8_UNORM = 65,
174 | DXGI_FORMAT_R1_UNORM = 66,
175 | DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67,
176 | DXGI_FORMAT_R8G8_B8G8_UNORM = 68,
177 | DXGI_FORMAT_G8R8_G8B8_UNORM = 69,
178 | DXGI_FORMAT_BC1_TYPELESS = 70,
179 | DXGI_FORMAT_BC1_UNORM = 71,
180 | DXGI_FORMAT_BC1_UNORM_SRGB = 72,
181 | DXGI_FORMAT_BC2_TYPELESS = 73,
182 | DXGI_FORMAT_BC2_UNORM = 74,
183 | DXGI_FORMAT_BC2_UNORM_SRGB = 75,
184 | DXGI_FORMAT_BC3_TYPELESS = 76,
185 | DXGI_FORMAT_BC3_UNORM = 77,
186 | DXGI_FORMAT_BC3_UNORM_SRGB = 78,
187 | DXGI_FORMAT_BC4_TYPELESS = 79,
188 | DXGI_FORMAT_BC4_UNORM = 80,
189 | DXGI_FORMAT_BC4_SNORM = 81,
190 | DXGI_FORMAT_BC5_TYPELESS = 82,
191 | DXGI_FORMAT_BC5_UNORM = 83,
192 | DXGI_FORMAT_BC5_SNORM = 84,
193 | DXGI_FORMAT_B5G6R5_UNORM = 85,
194 | DXGI_FORMAT_B5G5R5A1_UNORM = 86,
195 | DXGI_FORMAT_B8G8R8A8_UNORM = 87,
196 | DXGI_FORMAT_B8G8R8X8_UNORM = 88,
197 | DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89,
198 | DXGI_FORMAT_B8G8R8A8_TYPELESS = 90,
199 | DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91,
200 | DXGI_FORMAT_B8G8R8X8_TYPELESS = 92,
201 | DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93,
202 | DXGI_FORMAT_BC6H_TYPELESS = 94,
203 | DXGI_FORMAT_BC6H_UF16 = 95,
204 | DXGI_FORMAT_BC6H_SF16 = 96,
205 | DXGI_FORMAT_BC7_TYPELESS = 97,
206 | DXGI_FORMAT_BC7_UNORM = 98,
207 | DXGI_FORMAT_BC7_UNORM_SRGB = 99,
208 | DXGI_FORMAT_AYUV = 100,
209 | DXGI_FORMAT_Y410 = 101,
210 | DXGI_FORMAT_Y416 = 102,
211 | DXGI_FORMAT_NV12 = 103,
212 | DXGI_FORMAT_P010 = 104,
213 | DXGI_FORMAT_P016 = 105,
214 | DXGI_FORMAT_420_OPAQUE = 106,
215 | DXGI_FORMAT_YUY2 = 107,
216 | DXGI_FORMAT_Y210 = 108,
217 | DXGI_FORMAT_Y216 = 109,
218 | DXGI_FORMAT_NV11 = 110,
219 | DXGI_FORMAT_AI44 = 111,
220 | DXGI_FORMAT_IA44 = 112,
221 | DXGI_FORMAT_P8 = 113,
222 | DXGI_FORMAT_A8P8 = 114,
223 | DXGI_FORMAT_B4G4R4A4_UNORM = 115,
224 |
225 | DXGI_FORMAT_P208 = 130,
226 | DXGI_FORMAT_V208 = 131,
227 | DXGI_FORMAT_V408 = 132,
228 |
229 |
230 | DXGI_FORMAT_FORCE_UINT = 0xffffffff
231 | } DXGI_FORMAT;
232 |
233 | #pragma pack(pop)
234 |
235 | #define GC_MAPPING_FLAGS (FILE_MAP_READ | FILE_MAP_WRITE)
236 |
237 | static inline HANDLE create_hook_info(DWORD id)
238 | {
239 | wchar_t new_name[64];
240 | _snwprintf(new_name, 64, L"%s%lu", SHMEM_HOOK_INFO, id);
241 |
242 | return CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
243 | sizeof(struct hook_info), new_name);
244 | }
245 |
--------------------------------------------------------------------------------
/Nox/funchook.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "funchook.h"
4 |
5 | #define JMP_64_SIZE 14
6 | #define JMP_32_SIZE 5
7 |
8 | #define X86_NOP 0x90
9 | #define X86_JMP_NEG_5 0xF9EB
10 |
11 | static inline void fix_permissions(void *addr, size_t size)
12 | {
13 | DWORD protect_val;
14 | VirtualProtect(addr, size, PAGE_EXECUTE_READWRITE, &protect_val);
15 | }
16 |
17 | void hook_init(struct func_hook *hook, void *func_addr, void *hook_addr,
18 | const char *name)
19 | {
20 | memset(hook, 0, sizeof(*hook));
21 |
22 | hook->func_addr = (uintptr_t)func_addr;
23 | hook->hook_addr = (uintptr_t)hook_addr;
24 | hook->name = name;
25 |
26 | fix_permissions((void *)(hook->func_addr - JMP_32_SIZE),
27 | JMP_64_SIZE + JMP_32_SIZE);
28 |
29 | memcpy(hook->unhook_data, func_addr, JMP_64_SIZE);
30 | }
31 |
32 | static inline size_t patch_size(struct func_hook *hook)
33 | {
34 | return hook->is_64bit_jump ? JMP_64_SIZE : JMP_32_SIZE;
35 | }
36 |
37 | static const uint8_t longjmp64[6] = {0xFF, 0x25, 0x00, 0x00, 0x00, 0x00};
38 |
39 | static inline void rehook64(struct func_hook *hook)
40 | {
41 | uint8_t data[JMP_64_SIZE];
42 | uintptr_t *ptr_loc = (uintptr_t *)((uint8_t *)data + sizeof(longjmp64));
43 |
44 | fix_permissions((void *)hook->func_addr, JMP_64_SIZE);
45 |
46 | memcpy(data, (void *)hook->func_addr, JMP_64_SIZE);
47 | memcpy(data, longjmp64, sizeof(longjmp64));
48 | *ptr_loc = hook->hook_addr;
49 |
50 | hook->call_addr = (void *)hook->func_addr;
51 | hook->type = HOOKTYPE_FORWARD_OVERWRITE;
52 | hook->hooked = true;
53 |
54 | memcpy((void *)hook->func_addr, data, JMP_64_SIZE);
55 | }
56 |
57 | static inline void hook_reverse_new(struct func_hook *hook, uint8_t *p)
58 | {
59 | hook->call_addr = (void *)(hook->func_addr + 2);
60 | hook->type = HOOKTYPE_REVERSE_CHAIN;
61 | hook->hooked = true;
62 |
63 | p[0] = 0xE9;
64 | *((uint32_t *)&p[1]) = (uint32_t)(hook->hook_addr - hook->func_addr);
65 | *((uint16_t *)&p[5]) = X86_JMP_NEG_5;
66 | }
67 |
68 | static inline void hook_reverse_chain(struct func_hook *hook, uint8_t *p)
69 | {
70 | if (hook->type != HOOKTYPE_FORWARD_OVERWRITE)
71 | return;
72 |
73 | hook->call_addr = (void *)(hook->func_addr + *((int32_t *)&p[1]));
74 | hook->type = HOOKTYPE_REVERSE_CHAIN;
75 | hook->hooked = true;
76 |
77 | *((uint32_t *)&p[1]) = (uint32_t)(hook->hook_addr - hook->func_addr);
78 | }
79 |
80 | static inline void hook_forward_chain(struct func_hook *hook, uint8_t *p,
81 | intptr_t offset)
82 | {
83 | int32_t cur_offset = *(int32_t *)&p[6];
84 |
85 | if (hook->type != HOOKTYPE_FORWARD_OVERWRITE)
86 | return;
87 |
88 | hook->call_addr = (void *)(hook->func_addr + JMP_32_SIZE + cur_offset);
89 | hook->type = HOOKTYPE_FORWARD_CHAIN;
90 | hook->hooked = true;
91 |
92 | *((int32_t *)&p[6]) = (int32_t)offset;
93 | }
94 |
95 | static inline void hook_forward_overwrite(struct func_hook *hook,
96 | intptr_t offset)
97 | {
98 | uint8_t *ptr = (uint8_t *)hook->func_addr;
99 |
100 | hook->call_addr = (void *)hook->func_addr;
101 | hook->type = HOOKTYPE_FORWARD_OVERWRITE;
102 | hook->hooked = true;
103 |
104 | *(ptr++) = 0xE9;
105 | *((int32_t *)ptr) = (int32_t)offset;
106 | }
107 |
108 | static inline void rehook32(struct func_hook *hook, bool force, intptr_t offset)
109 | {
110 | fix_permissions((void *)(hook->func_addr - JMP_32_SIZE),
111 | JMP_32_SIZE * 2);
112 |
113 | if (force || !hook->started) {
114 | uint8_t *p = (uint8_t *)hook->func_addr - JMP_32_SIZE;
115 | size_t nop_count = 0;
116 |
117 | /* check for reverse chain hook availability */
118 | for (size_t i = 0; i < JMP_32_SIZE; i++) {
119 | if (p[i] == X86_NOP)
120 | nop_count++;
121 | }
122 |
123 | if (nop_count == JMP_32_SIZE && p[5] == 0x8B && p[6] == 0xFF) {
124 | hook_reverse_new(hook, p);
125 |
126 | } else if (p[0] == 0xE9 &&
127 | *(uint16_t *)&p[5] == X86_JMP_NEG_5) {
128 | hook_reverse_chain(hook, p);
129 |
130 | } else if (p[5] == 0xE9) {
131 | hook_forward_chain(hook, p, offset);
132 |
133 | } else if (hook->type != HOOKTYPE_FORWARD_OVERWRITE) {
134 | hook->type = HOOKTYPE_FORWARD_OVERWRITE;
135 | }
136 |
137 | hook->started = true;
138 | }
139 |
140 | if (hook->type == HOOKTYPE_FORWARD_OVERWRITE) {
141 | hook_forward_overwrite(hook, offset);
142 | }
143 | }
144 |
145 | /*
146 | * Creates memory close to the target function, used to force the actual hook
147 | * to use a 32bit jump instead of a 64bit jump, thus preventing the chance of
148 | * overwriting adjacent functions, which can cause a crash. (by R1CH)
149 | */
150 | static void setup_64bit_bounce(struct func_hook *hook, intptr_t *offset)
151 | {
152 | MEMORY_BASIC_INFORMATION mbi;
153 | uintptr_t address;
154 | uintptr_t newdiff;
155 | SYSTEM_INFO si;
156 | bool success;
157 | int pagesize;
158 | int i;
159 |
160 | success = VirtualQueryEx(GetCurrentProcess(),
161 | (const void *)hook->func_addr, &mbi,
162 | sizeof(mbi));
163 | if (!success)
164 | return;
165 |
166 | GetSystemInfo(&si);
167 | pagesize = (int)si.dwAllocationGranularity;
168 |
169 | address = (uintptr_t)mbi.AllocationBase - pagesize;
170 | for (i = 0; i < 256; i++, address -= pagesize) {
171 | hook->bounce_addr = VirtualAlloc((LPVOID)address, pagesize,
172 | MEM_RESERVE | MEM_COMMIT,
173 | PAGE_EXECUTE_READWRITE);
174 | if (hook->bounce_addr)
175 | break;
176 | }
177 |
178 | if (!hook->bounce_addr) {
179 | address = (uintptr_t)mbi.AllocationBase + mbi.RegionSize +
180 | pagesize;
181 | for (i = 0; i < 256; i++, address += pagesize) {
182 | hook->bounce_addr =
183 | VirtualAlloc((LPVOID)address, pagesize,
184 | MEM_RESERVE | MEM_COMMIT,
185 | PAGE_EXECUTE_READWRITE);
186 | if (hook->bounce_addr)
187 | break;
188 | }
189 | }
190 |
191 | if (!hook->bounce_addr)
192 | return;
193 |
194 | if ((hook->func_addr + 5) > (uintptr_t)hook->bounce_addr)
195 | newdiff = hook->func_addr + 5 - (uintptr_t)hook->bounce_addr;
196 | else
197 | newdiff = (uintptr_t)hook->bounce_addr - hook->func_addr + 5;
198 |
199 | if (newdiff <= 0x7ffffff0) {
200 | uint8_t *addr = (uint8_t *)hook->bounce_addr;
201 |
202 | FillMemory(hook->bounce_addr, pagesize, 0xCC);
203 |
204 | *(addr++) = 0xFF;
205 | *(addr++) = 0x25;
206 | *((uint32_t *)addr) = 0;
207 | *((uint64_t *)(addr + 4)) = hook->hook_addr;
208 |
209 | hook->hook_addr = (uint64_t)hook->bounce_addr;
210 | *offset = hook->hook_addr - hook->func_addr - JMP_32_SIZE;
211 | hook->is_64bit_jump = false;
212 | }
213 | }
214 |
215 | void do_hook(struct func_hook *hook, bool force)
216 | {
217 | intptr_t offset;
218 |
219 | if (!force && hook->hooked)
220 | return;
221 |
222 | /* copy back the memory that was previously encountered to preserve
223 | * the current hook and any newer hooks on top */
224 | if (hook->started && !force) {
225 | uintptr_t addr;
226 | size_t size;
227 |
228 | if (hook->type == HOOKTYPE_REVERSE_CHAIN) {
229 | addr = hook->func_addr - JMP_32_SIZE;
230 | size = JMP_32_SIZE;
231 | } else {
232 | addr = hook->func_addr;
233 | size = patch_size(hook);
234 | }
235 |
236 | memcpy((void *)addr, hook->rehook_data, size);
237 | hook->hooked = true;
238 | return;
239 | }
240 |
241 | offset = hook->hook_addr - hook->func_addr - JMP_32_SIZE;
242 |
243 | #ifdef _WIN64
244 | hook->is_64bit_jump = (llabs(offset) >= 0x7fffffff);
245 |
246 | if (hook->is_64bit_jump) {
247 | if (!hook->attempted_bounce) {
248 | hook->attempted_bounce = true;
249 | setup_64bit_bounce(hook, &offset);
250 | }
251 |
252 | if (hook->is_64bit_jump) {
253 | rehook64(hook);
254 | return;
255 | }
256 | }
257 | #endif
258 |
259 | rehook32(hook, force, offset);
260 | }
261 |
262 | void unhook(struct func_hook *hook)
263 | {
264 | uintptr_t addr;
265 | size_t size;
266 | if (!hook->hooked)
267 | return;
268 |
269 | if (hook->type == HOOKTYPE_REVERSE_CHAIN) {
270 | size = JMP_32_SIZE;
271 | addr = (hook->func_addr - JMP_32_SIZE);
272 | } else {
273 | size = patch_size(hook);
274 | addr = hook->func_addr;
275 | }
276 |
277 | fix_permissions((void *)addr, size);
278 | memcpy(hook->rehook_data, (void *)addr, size);
279 |
280 | if (hook->type == HOOKTYPE_FORWARD_OVERWRITE)
281 | memcpy((void *)hook->func_addr, hook->unhook_data, size);
282 |
283 | hook->hooked = false;
284 | }
285 |
--------------------------------------------------------------------------------
/Nox/libOpenGL/gl-vertexbuffer.c:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | Copyright (C) 2013 by Hugh Bailey
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 2 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | ******************************************************************************/
17 |
18 | #include
19 | #include "gl-subsystem.h"
20 |
21 | static bool create_buffers(struct gs_vertex_buffer *vb)
22 | {
23 | GLenum usage = vb->dynamic ? GL_STREAM_DRAW : GL_STATIC_DRAW;
24 | size_t i;
25 |
26 | if (!gl_create_buffer(GL_ARRAY_BUFFER, &vb->vertex_buffer,
27 | vb->data->num * sizeof(struct vec3),
28 | vb->data->points, usage))
29 | return false;
30 |
31 | if (vb->data->normals) {
32 | if (!gl_create_buffer(GL_ARRAY_BUFFER, &vb->normal_buffer,
33 | vb->data->num * sizeof(struct vec3),
34 | vb->data->normals, usage))
35 | return false;
36 | }
37 |
38 | if (vb->data->tangents) {
39 | if (!gl_create_buffer(GL_ARRAY_BUFFER, &vb->tangent_buffer,
40 | vb->data->num * sizeof(struct vec3),
41 | vb->data->tangents, usage))
42 | return false;
43 | }
44 |
45 | if (vb->data->colors) {
46 | if (!gl_create_buffer(GL_ARRAY_BUFFER, &vb->color_buffer,
47 | vb->data->num * sizeof(uint32_t),
48 | vb->data->colors, usage))
49 | return false;
50 | }
51 |
52 | da_reserve(vb->uv_buffers, vb->data->num_tex);
53 | da_reserve(vb->uv_sizes, vb->data->num_tex);
54 |
55 | for (i = 0; i < vb->data->num_tex; i++) {
56 | GLuint tex_buffer;
57 | struct gs_tvertarray *tv = vb->data->tvarray + i;
58 | size_t size = vb->data->num * sizeof(float) * tv->width;
59 |
60 | if (!gl_create_buffer(GL_ARRAY_BUFFER, &tex_buffer, size,
61 | tv->array, usage))
62 | return false;
63 |
64 | da_push_back(vb->uv_buffers, &tex_buffer);
65 | da_push_back(vb->uv_sizes, &tv->width);
66 | }
67 |
68 | if (!vb->dynamic) {
69 | gs_vbdata_destroy(vb->data);
70 | vb->data = NULL;
71 | }
72 |
73 | if (!gl_gen_vertex_arrays(1, &vb->vao))
74 | return false;
75 |
76 | return true;
77 | }
78 |
79 | gs_vertbuffer_t *device_vertexbuffer_create(gs_device_t *device,
80 | struct gs_vb_data *data,
81 | uint32_t flags)
82 | {
83 | struct gs_vertex_buffer *vb = bzalloc(sizeof(struct gs_vertex_buffer));
84 | vb->device = device;
85 | vb->data = data;
86 | vb->num = data->num;
87 | vb->dynamic = flags & GS_DYNAMIC;
88 |
89 | if (!create_buffers(vb)) {
90 | blog(LOG_ERROR, "device_vertexbuffer_create (GL) failed");
91 | gs_vertexbuffer_destroy(vb);
92 | return NULL;
93 | }
94 |
95 | return vb;
96 | }
97 |
98 | void gs_vertexbuffer_destroy(gs_vertbuffer_t *vb)
99 | {
100 | if (vb) {
101 | if (vb->vertex_buffer)
102 | gl_delete_buffers(1, &vb->vertex_buffer);
103 | if (vb->normal_buffer)
104 | gl_delete_buffers(1, &vb->normal_buffer);
105 | if (vb->tangent_buffer)
106 | gl_delete_buffers(1, &vb->tangent_buffer);
107 | if (vb->color_buffer)
108 | gl_delete_buffers(1, &vb->color_buffer);
109 | if (vb->uv_buffers.num)
110 | gl_delete_buffers((GLsizei)vb->uv_buffers.num,
111 | vb->uv_buffers.array);
112 |
113 | if (vb->vao)
114 | gl_delete_vertex_arrays(1, &vb->vao);
115 |
116 | da_free(vb->uv_sizes);
117 | da_free(vb->uv_buffers);
118 | gs_vbdata_destroy(vb->data);
119 |
120 | bfree(vb);
121 | }
122 | }
123 |
124 | static inline void gs_vertexbuffer_flush_internal(gs_vertbuffer_t *vb,
125 | const struct gs_vb_data *data)
126 | {
127 | size_t i;
128 | size_t num_tex = data->num_tex < vb->data->num_tex ? data->num_tex
129 | : vb->data->num_tex;
130 |
131 | if (!vb->dynamic) {
132 | blog(LOG_ERROR, "vertex buffer is not dynamic");
133 | goto failed;
134 | }
135 |
136 | if (data->points) {
137 | if (!update_buffer(GL_ARRAY_BUFFER, vb->vertex_buffer,
138 | data->points,
139 | data->num * sizeof(struct vec3)))
140 | goto failed;
141 | }
142 |
143 | if (vb->normal_buffer && data->normals) {
144 | if (!update_buffer(GL_ARRAY_BUFFER, vb->normal_buffer,
145 | data->normals,
146 | data->num * sizeof(struct vec3)))
147 | goto failed;
148 | }
149 |
150 | if (vb->tangent_buffer && data->tangents) {
151 | if (!update_buffer(GL_ARRAY_BUFFER, vb->tangent_buffer,
152 | data->tangents,
153 | data->num * sizeof(struct vec3)))
154 | goto failed;
155 | }
156 |
157 | if (vb->color_buffer && data->colors) {
158 | if (!update_buffer(GL_ARRAY_BUFFER, vb->color_buffer,
159 | data->colors, data->num * sizeof(uint32_t)))
160 | goto failed;
161 | }
162 |
163 | for (i = 0; i < num_tex; i++) {
164 | GLuint buffer = vb->uv_buffers.array[i];
165 | struct gs_tvertarray *tv = data->tvarray + i;
166 | size_t size = data->num * tv->width * sizeof(float);
167 |
168 | if (!update_buffer(GL_ARRAY_BUFFER, buffer, tv->array, size))
169 | goto failed;
170 | }
171 |
172 | return;
173 |
174 | failed:
175 | blog(LOG_ERROR, "gs_vertexbuffer_flush (GL) failed");
176 | }
177 |
178 | void gs_vertexbuffer_flush(gs_vertbuffer_t *vb)
179 | {
180 | gs_vertexbuffer_flush_internal(vb, vb->data);
181 | }
182 |
183 | void gs_vertexbuffer_flush_direct(gs_vertbuffer_t *vb,
184 | const struct gs_vb_data *data)
185 | {
186 | gs_vertexbuffer_flush_internal(vb, data);
187 | }
188 |
189 | struct gs_vb_data *gs_vertexbuffer_get_data(const gs_vertbuffer_t *vb)
190 | {
191 | return vb->data;
192 | }
193 |
194 | static inline GLuint get_vb_buffer(struct gs_vertex_buffer *vb,
195 | enum attrib_type type, size_t index,
196 | GLint *width, GLenum *gl_type)
197 | {
198 | *gl_type = GL_FLOAT;
199 | *width = 4;
200 |
201 | if (type == ATTRIB_POSITION) {
202 | return vb->vertex_buffer;
203 | } else if (type == ATTRIB_NORMAL) {
204 | return vb->normal_buffer;
205 | } else if (type == ATTRIB_TANGENT) {
206 | return vb->tangent_buffer;
207 | } else if (type == ATTRIB_COLOR) {
208 | *gl_type = GL_UNSIGNED_BYTE;
209 | return vb->color_buffer;
210 | } else if (type == ATTRIB_TEXCOORD) {
211 | if (vb->uv_buffers.num <= index)
212 | return 0;
213 |
214 | *width = (GLint)vb->uv_sizes.array[index];
215 | return vb->uv_buffers.array[index];
216 | }
217 |
218 | return 0;
219 | }
220 |
221 | static bool load_vb_buffer(struct shader_attrib *attrib,
222 | struct gs_vertex_buffer *vb, GLint id)
223 | {
224 | GLenum type;
225 | GLint width;
226 | GLuint buffer;
227 | bool success = true;
228 |
229 | buffer = get_vb_buffer(vb, attrib->type, attrib->index, &width, &type);
230 | if (!buffer) {
231 | blog(LOG_ERROR, "Vertex buffer does not have the required "
232 | "inputs for vertex shader");
233 | return false;
234 | }
235 |
236 | if (!gl_bind_buffer(GL_ARRAY_BUFFER, buffer))
237 | return false;
238 |
239 | glVertexAttribPointer(id, width, type, GL_TRUE, 0, 0);
240 | if (!gl_success("glVertexAttribPointer"))
241 | success = false;
242 |
243 | glEnableVertexAttribArray(id);
244 | if (!gl_success("glEnableVertexAttribArray"))
245 | success = false;
246 |
247 | if (!gl_bind_buffer(GL_ARRAY_BUFFER, 0))
248 | success = false;
249 |
250 | return success;
251 | }
252 |
253 | bool load_vb_buffers(struct gs_program *program, struct gs_vertex_buffer *vb,
254 | struct gs_index_buffer *ib)
255 | {
256 | struct gs_shader *shader = program->vertex_shader;
257 | size_t i;
258 |
259 | if (!gl_bind_vertex_array(vb->vao))
260 | return false;
261 |
262 | for (i = 0; i < shader->attribs.num; i++) {
263 | struct shader_attrib *attrib = shader->attribs.array + i;
264 | if (!load_vb_buffer(attrib, vb, program->attribs.array[i]))
265 | return false;
266 | }
267 |
268 | if (ib && !gl_bind_buffer(GL_ELEMENT_ARRAY_BUFFER, ib->buffer))
269 | return false;
270 |
271 | return true;
272 | }
273 |
274 | void device_load_vertexbuffer(gs_device_t *device, gs_vertbuffer_t *vb)
275 | {
276 | device->cur_vertex_buffer = vb;
277 | }
278 |
--------------------------------------------------------------------------------
/Nox/libOpenGL/gl-texture2d.c:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | Copyright (C) 2013 by Hugh Bailey
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 2 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | ******************************************************************************/
17 |
18 | #include "gl-subsystem.h"
19 |
20 | static bool upload_texture_2d(struct gs_texture_2d *tex, const uint8_t **data)
21 | {
22 | uint32_t row_size = tex->width * gs_get_format_bpp(tex->base.format);
23 | uint32_t tex_size = tex->height * row_size / 8;
24 | uint32_t num_levels = tex->base.levels;
25 | bool compressed = gs_is_compressed_format(tex->base.format);
26 | bool success;
27 |
28 | if (!num_levels)
29 | num_levels = gs_get_total_levels(tex->width, tex->height);
30 |
31 | if (!gl_bind_texture(GL_TEXTURE_2D, tex->base.texture))
32 | return false;
33 |
34 | success = gl_init_face(GL_TEXTURE_2D, tex->base.gl_type, num_levels,
35 | tex->base.gl_format,
36 | tex->base.gl_internal_format, compressed,
37 | tex->width, tex->height, tex_size, &data);
38 |
39 | if (!gl_tex_param_i(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL,
40 | num_levels - 1))
41 | success = false;
42 | if (!gl_bind_texture(GL_TEXTURE_2D, 0))
43 | success = false;
44 |
45 | return success;
46 | }
47 |
48 | static bool create_pixel_unpack_buffer(struct gs_texture_2d *tex)
49 | {
50 | GLsizeiptr size;
51 | bool success = true;
52 |
53 | if (!gl_gen_buffers(1, &tex->unpack_buffer))
54 | return false;
55 |
56 | if (!gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, tex->unpack_buffer))
57 | return false;
58 |
59 | size = tex->width * gs_get_format_bpp(tex->base.format);
60 | if (!gs_is_compressed_format(tex->base.format)) {
61 | size /= 8;
62 | size = (size + 3) & 0xFFFFFFFC;
63 | size *= tex->height;
64 | } else {
65 | size *= tex->height;
66 | size /= 8;
67 | }
68 |
69 | glBufferData(GL_PIXEL_UNPACK_BUFFER, size, 0, GL_DYNAMIC_DRAW);
70 | if (!gl_success("glBufferData"))
71 | success = false;
72 |
73 | if (!gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, 0))
74 | success = false;
75 |
76 | return success;
77 | }
78 |
79 | gs_texture_t *device_texture_create(gs_device_t *device, uint32_t width,
80 | uint32_t height,
81 | enum gs_color_format color_format,
82 | uint32_t levels, const uint8_t **data,
83 | uint32_t flags)
84 | {
85 | struct gs_texture_2d *tex = bzalloc(sizeof(struct gs_texture_2d));
86 | tex->base.device = device;
87 | tex->base.type = GS_TEXTURE_2D;
88 | tex->base.format = color_format;
89 | tex->base.levels = levels;
90 | tex->base.gl_format = convert_gs_format(color_format);
91 | tex->base.gl_internal_format = convert_gs_internal_format(color_format);
92 | tex->base.gl_type = get_gl_format_type(color_format);
93 | tex->base.gl_target = GL_TEXTURE_2D;
94 | tex->base.is_dynamic = (flags & GS_DYNAMIC) != 0;
95 | tex->base.is_render_target = (flags & GS_RENDER_TARGET) != 0;
96 | tex->base.is_dummy = (flags & GS_GL_DUMMYTEX) != 0;
97 | tex->base.gen_mipmaps = (flags & GS_BUILD_MIPMAPS) != 0;
98 | tex->width = width;
99 | tex->height = height;
100 |
101 | if (!gl_gen_textures(1, &tex->base.texture))
102 | goto fail;
103 |
104 | if (!tex->base.is_dummy) {
105 | if (tex->base.is_dynamic && !create_pixel_unpack_buffer(tex))
106 | goto fail;
107 | if (!upload_texture_2d(tex, data))
108 | goto fail;
109 | } else {
110 | if (!gl_bind_texture(GL_TEXTURE_2D, tex->base.texture))
111 | goto fail;
112 |
113 | uint32_t row_size =
114 | tex->width * gs_get_format_bpp(tex->base.format);
115 | uint32_t tex_size = tex->height * row_size / 8;
116 | bool compressed = gs_is_compressed_format(tex->base.format);
117 | bool did_init = gl_init_face(GL_TEXTURE_2D, tex->base.gl_type,
118 | 1, tex->base.gl_format,
119 | tex->base.gl_internal_format,
120 | compressed, tex->width,
121 | tex->height, tex_size, NULL);
122 | did_init =
123 | gl_tex_param_i(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
124 |
125 | bool did_unbind = gl_bind_texture(GL_TEXTURE_2D, 0);
126 | if (!did_init || !did_unbind)
127 | goto fail;
128 | }
129 |
130 | return (gs_texture_t *)tex;
131 |
132 | fail:
133 | gs_texture_destroy((gs_texture_t *)tex);
134 | blog(LOG_ERROR, "device_texture_create (GL) failed");
135 | return NULL;
136 | }
137 |
138 | static inline bool is_texture_2d(const gs_texture_t *tex, const char *func)
139 | {
140 | bool is_tex2d = tex->type == GS_TEXTURE_2D;
141 | if (!is_tex2d)
142 | blog(LOG_ERROR, "%s (GL) failed: Not a 2D texture", func);
143 | return is_tex2d;
144 | }
145 |
146 | void gs_texture_destroy(gs_texture_t *tex)
147 | {
148 | struct gs_texture_2d *tex2d = (struct gs_texture_2d *)tex;
149 | if (!tex)
150 | return;
151 |
152 | if (!is_texture_2d(tex, "gs_texture_destroy"))
153 | return;
154 |
155 | if (tex->cur_sampler)
156 | gs_samplerstate_destroy(tex->cur_sampler);
157 |
158 | if (!tex->is_dummy && tex->is_dynamic && tex2d->unpack_buffer)
159 | gl_delete_buffers(1, &tex2d->unpack_buffer);
160 |
161 | if (tex->texture)
162 | gl_delete_textures(1, &tex->texture);
163 |
164 | if (tex->fbo)
165 | fbo_info_destroy(tex->fbo);
166 |
167 | bfree(tex);
168 | }
169 |
170 | uint32_t gs_texture_get_width(const gs_texture_t *tex)
171 | {
172 | const struct gs_texture_2d *tex2d = (const struct gs_texture_2d *)tex;
173 | if (!is_texture_2d(tex, "gs_texture_get_width"))
174 | return 0;
175 |
176 | return tex2d->width;
177 | }
178 |
179 | uint32_t gs_texture_get_height(const gs_texture_t *tex)
180 | {
181 | const struct gs_texture_2d *tex2d = (const struct gs_texture_2d *)tex;
182 | if (!is_texture_2d(tex, "gs_texture_get_height"))
183 | return 0;
184 |
185 | return tex2d->height;
186 | }
187 |
188 | enum gs_color_format gs_texture_get_color_format(const gs_texture_t *tex)
189 | {
190 | return tex->format;
191 | }
192 |
193 | bool gs_texture_map(gs_texture_t *tex, uint8_t **ptr, uint32_t *linesize)
194 | {
195 | struct gs_texture_2d *tex2d = (struct gs_texture_2d *)tex;
196 |
197 | if (!is_texture_2d(tex, "gs_texture_map"))
198 | goto fail;
199 |
200 | if (!tex2d->base.is_dynamic) {
201 | blog(LOG_ERROR, "Texture is not dynamic");
202 | goto fail;
203 | }
204 |
205 | if (!gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, tex2d->unpack_buffer))
206 | goto fail;
207 |
208 | *ptr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
209 | if (!gl_success("glMapBuffer"))
210 | goto fail;
211 |
212 | gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, 0);
213 |
214 | *linesize = tex2d->width * gs_get_format_bpp(tex->format) / 8;
215 | *linesize = (*linesize + 3) & 0xFFFFFFFC;
216 | return true;
217 |
218 | fail:
219 | blog(LOG_ERROR, "gs_texture_map (GL) failed");
220 | return false;
221 | }
222 |
223 | void gs_texture_unmap(gs_texture_t *tex)
224 | {
225 | struct gs_texture_2d *tex2d = (struct gs_texture_2d *)tex;
226 | if (!is_texture_2d(tex, "gs_texture_unmap"))
227 | goto failed;
228 |
229 | if (!gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, tex2d->unpack_buffer))
230 | goto failed;
231 |
232 | glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
233 | if (!gl_success("glUnmapBuffer"))
234 | goto failed;
235 |
236 | if (!gl_bind_texture(GL_TEXTURE_2D, tex2d->base.texture))
237 | goto failed;
238 |
239 | glTexImage2D(GL_TEXTURE_2D, 0, tex->gl_internal_format, tex2d->width,
240 | tex2d->height, 0, tex->gl_format, tex->gl_type, 0);
241 | if (!gl_success("glTexImage2D"))
242 | goto failed;
243 |
244 | gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, 0);
245 | gl_bind_texture(GL_TEXTURE_2D, 0);
246 | return;
247 |
248 | failed:
249 | gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, 0);
250 | gl_bind_texture(GL_TEXTURE_2D, 0);
251 | blog(LOG_ERROR, "gs_texture_unmap (GL) failed");
252 | }
253 |
254 | bool gs_texture_is_rect(const gs_texture_t *tex)
255 | {
256 | const struct gs_texture_2d *tex2d = (const struct gs_texture_2d *)tex;
257 | if (!is_texture_2d(tex, "gs_texture_unmap")) {
258 | blog(LOG_ERROR, "gs_texture_is_rect (GL) failed");
259 | return false;
260 | }
261 |
262 | return tex2d->base.gl_target == GL_TEXTURE_RECTANGLE;
263 | }
264 |
265 | void *gs_texture_get_obj(gs_texture_t *tex)
266 | {
267 | struct gs_texture_2d *tex2d = (struct gs_texture_2d *)tex;
268 | if (!is_texture_2d(tex, "gs_texture_unmap")) {
269 | blog(LOG_ERROR, "gs_texture_get_obj (GL) failed");
270 | return NULL;
271 | }
272 |
273 | return &tex2d->base.texture;
274 | }
275 |
--------------------------------------------------------------------------------
/Nox/graphic-hook/d3d12-capture.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "graphics-hook.h"
3 |
4 | #if COMPILE_D3D12_HOOK
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | #include "dxgi-helpers.hpp"
11 | #include "../funchook.h"
12 |
13 | #define MAX_BACKBUFFERS 8
14 |
15 | struct d3d12_data {
16 | ID3D12Device *device; /* do not release */
17 | uint32_t base_cx;
18 | uint32_t base_cy;
19 | uint32_t cx;
20 | uint32_t cy;
21 | DXGI_FORMAT format;
22 | bool using_shtex;
23 | bool using_scale;
24 | bool multisampled;
25 | bool dxgi_1_4;
26 |
27 | ID3D11Device *device11;
28 | ID3D11DeviceContext *context11;
29 | ID3D11On12Device *device11on12;
30 |
31 | union {
32 | struct {
33 | struct shtex_data *shtex_info;
34 | ID3D11Resource *backbuffer11[MAX_BACKBUFFERS];
35 | UINT backbuffer_count;
36 | UINT cur_backbuffer;
37 | ID3D11Texture2D *copy_tex;
38 | HANDLE handle;
39 | };
40 | };
41 | };
42 |
43 | static struct d3d12_data data = {};
44 |
45 | void d3d12_free(void)
46 | {
47 | if (data.copy_tex)
48 | data.copy_tex->Release();
49 | for (size_t i = 0; i < data.backbuffer_count; i++) {
50 | if (data.backbuffer11[i])
51 | data.backbuffer11[i]->Release();
52 | }
53 | if (data.device11)
54 | data.device11->Release();
55 | if (data.context11)
56 | data.context11->Release();
57 | if (data.device11on12)
58 | data.device11on12->Release();
59 |
60 | capture_free();
61 |
62 | memset(&data, 0, sizeof(data));
63 |
64 | hlog("----------------- d3d12 capture freed ----------------");
65 | }
66 |
67 | struct bb_info {
68 | ID3D12Resource *backbuffer[MAX_BACKBUFFERS];
69 | UINT count;
70 | };
71 |
72 | static bool create_d3d12_tex(bb_info &bb)
73 | {
74 | D3D11_RESOURCE_FLAGS rf11 = {};
75 | HRESULT hr;
76 |
77 | if (!bb.count)
78 | return false;
79 |
80 | data.backbuffer_count = bb.count;
81 |
82 | for (UINT i = 0; i < bb.count; i++) {
83 | hr = data.device11on12->CreateWrappedResource(
84 | bb.backbuffer[i], &rf11,
85 | D3D12_RESOURCE_STATE_COPY_SOURCE,
86 | D3D12_RESOURCE_STATE_PRESENT, __uuidof(ID3D11Resource),
87 | (void **)&data.backbuffer11[i]);
88 | if (FAILED(hr)) {
89 | hlog_hr("create_d3d12_tex: failed to create "
90 | "backbuffer11",
91 | hr);
92 | return false;
93 | }
94 | }
95 |
96 | D3D11_TEXTURE2D_DESC desc11 = {};
97 | desc11.Width = data.cx;
98 | desc11.Height = data.cy;
99 | desc11.MipLevels = 1;
100 | desc11.ArraySize = 1;
101 | desc11.Format = data.format;
102 | desc11.SampleDesc.Count = 1;
103 | desc11.BindFlags = D3D11_BIND_SHADER_RESOURCE;
104 | desc11.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
105 |
106 | hr = data.device11->CreateTexture2D(&desc11, nullptr, &data.copy_tex);
107 | if (FAILED(hr)) {
108 | hlog_hr("create_d3d12_tex: creation of d3d11 copy tex failed",
109 | hr);
110 | return false;
111 | }
112 |
113 | for (UINT i = 0; i < bb.count; i++) {
114 | data.device11on12->ReleaseWrappedResources(
115 | &data.backbuffer11[i], 1);
116 | }
117 |
118 | IDXGIResource *dxgi_res;
119 | hr = data.copy_tex->QueryInterface(__uuidof(IDXGIResource),
120 | (void **)&dxgi_res);
121 | if (FAILED(hr)) {
122 | hlog_hr("create_d3d12_tex: failed to query "
123 | "IDXGIResource interface from texture",
124 | hr);
125 | return false;
126 | }
127 |
128 | hr = dxgi_res->GetSharedHandle(&data.handle);
129 | dxgi_res->Release();
130 | if (FAILED(hr)) {
131 | hlog_hr("create_d3d12_tex: failed to get shared handle", hr);
132 | return false;
133 | }
134 |
135 | return true;
136 | }
137 |
138 | typedef PFN_D3D11ON12_CREATE_DEVICE create_11_on_12_t;
139 |
140 | static bool d3d12_init_11on12(void)
141 | {
142 | static HMODULE d3d11 = nullptr;
143 | static create_11_on_12_t create_11_on_12 = nullptr;
144 | static bool initialized_11 = false;
145 | static bool initialized_func = false;
146 | HRESULT hr;
147 |
148 | if (!initialized_11 && !d3d11) {
149 | d3d11 = load_system_library("d3d11.dll");
150 | if (!d3d11) {
151 | hlog("d3d12_init_11on12: failed to load d3d11");
152 | }
153 | initialized_11 = true;
154 | }
155 |
156 | if (!d3d11) {
157 | return false;
158 | }
159 |
160 | if (!initialized_func && !create_11_on_12) {
161 | create_11_on_12 = (create_11_on_12_t)GetProcAddress(
162 | d3d11, "D3D11On12CreateDevice");
163 | if (!create_11_on_12) {
164 | hlog("d3d12_init_11on12: Failed to get "
165 | "D3D11On12CreateDevice address");
166 | }
167 |
168 | initialized_func = true;
169 | }
170 |
171 | if (!create_11_on_12) {
172 | return false;
173 | }
174 |
175 | hr = create_11_on_12(data.device, 0, nullptr, 0, nullptr, 0, 0,
176 | &data.device11, &data.context11, nullptr);
177 | if (FAILED(hr)) {
178 | hlog_hr("d3d12_init_11on12: failed to create 11 device", hr);
179 | return false;
180 | }
181 |
182 | data.device11->QueryInterface(__uuidof(ID3D11On12Device),
183 | (void **)&data.device11on12);
184 | if (FAILED(hr)) {
185 | hlog_hr("d3d12_init_11on12: failed to query 11on12 device", hr);
186 | return false;
187 | }
188 |
189 | return true;
190 | }
191 |
192 | static bool d3d12_shtex_init(HWND window, bb_info &bb)
193 | {
194 | if (!d3d12_init_11on12()) {
195 | return false;
196 | }
197 | if (!create_d3d12_tex(bb)) {
198 | return false;
199 | }
200 | if (!capture_init_shtex(&data.shtex_info, window, data.base_cx,
201 | data.base_cy, data.cx, data.cy, data.format,
202 | false, (uintptr_t)data.handle)) {
203 | return false;
204 | }
205 |
206 | hlog("d3d12 shared texture capture successful");
207 | return true;
208 | }
209 |
210 | static inline bool d3d12_init_format(IDXGISwapChain *swap, HWND &window,
211 | bb_info &bb)
212 | {
213 | DXGI_SWAP_CHAIN_DESC desc;
214 | IDXGISwapChain3 *swap3;
215 | HRESULT hr;
216 |
217 | hr = swap->GetDesc(&desc);
218 | if (FAILED(hr)) {
219 | hlog_hr("d3d12_init_format: swap->GetDesc failed", hr);
220 | return false;
221 | }
222 |
223 | data.format = fix_dxgi_format(desc.BufferDesc.Format);
224 | data.multisampled = desc.SampleDesc.Count > 1;
225 | window = desc.OutputWindow;
226 | data.base_cx = desc.BufferDesc.Width;
227 | data.base_cy = desc.BufferDesc.Height;
228 |
229 | hr = swap->QueryInterface(__uuidof(IDXGISwapChain3), (void **)&swap3);
230 | if (SUCCEEDED(hr)) {
231 | data.dxgi_1_4 = true;
232 | hlog("We're DXGI1.4 boys!");
233 | swap3->Release();
234 | }
235 |
236 | hlog("Buffer count: %d, swap effect: %d", (int)desc.BufferCount,
237 | (int)desc.SwapEffect);
238 |
239 | bb.count = desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD
240 | ? 1
241 | : desc.BufferCount;
242 |
243 | if (bb.count == 1)
244 | data.dxgi_1_4 = false;
245 |
246 | if (bb.count > MAX_BACKBUFFERS) {
247 | hlog("Somehow it's using more than the max backbuffers. "
248 | "Not sure why anyone would do that.");
249 | bb.count = 1;
250 | data.dxgi_1_4 = false;
251 | }
252 |
253 | for (UINT i = 0; i < bb.count; i++) {
254 | hr = swap->GetBuffer(i, __uuidof(ID3D12Resource),
255 | (void **)&bb.backbuffer[i]);
256 | if (SUCCEEDED(hr)) {
257 | bb.backbuffer[i]->Release();
258 | } else {
259 | return false;
260 | }
261 | }
262 |
263 | if (data.using_scale) {
264 | data.cx = global_hook_info->cx;
265 | data.cy = global_hook_info->cy;
266 | } else {
267 | data.cx = desc.BufferDesc.Width;
268 | data.cy = desc.BufferDesc.Height;
269 | }
270 | return true;
271 | }
272 |
273 | static void d3d12_init(IDXGISwapChain *swap)
274 | {
275 | bool success = true;
276 | bb_info bb = {};
277 | HWND window;
278 | HRESULT hr;
279 |
280 | data.using_scale = global_hook_info->use_scale;
281 |
282 | hr = swap->GetDevice(__uuidof(ID3D12Device), (void **)&data.device);
283 | if (FAILED(hr)) {
284 | hlog_hr("d3d12_init: failed to get device from swap", hr);
285 | return;
286 | }
287 |
288 | data.device->Release();
289 |
290 | if (!d3d12_init_format(swap, window, bb)) {
291 | return;
292 | }
293 | if (data.using_scale) {
294 | hlog("d3d12_init: scaling currently unsupported; ignoring");
295 | }
296 | if (success) {
297 | if (global_hook_info->force_shmem) {
298 | hlog("d3d12_init: shared memory capture currently "
299 | "unsupported; ignoring");
300 | }
301 |
302 | success = d3d12_shtex_init(window, bb);
303 | }
304 |
305 | if (!success)
306 | d3d12_free();
307 | }
308 |
309 | static inline void d3d12_copy_texture(ID3D11Resource *dst, ID3D11Resource *src)
310 | {
311 | if (data.multisampled) {
312 | data.context11->ResolveSubresource(dst, 0, src, 0, data.format);
313 | } else {
314 | data.context11->CopyResource(dst, src);
315 | }
316 | }
317 |
318 | static inline void d3d12_shtex_capture(IDXGISwapChain *swap,
319 | bool capture_overlay)
320 | {
321 | bool dxgi_1_4 = data.dxgi_1_4;
322 | UINT cur_idx;
323 |
324 | if (dxgi_1_4) {
325 | IDXGISwapChain3 *swap3 =
326 | reinterpret_cast(swap);
327 | cur_idx = swap3->GetCurrentBackBufferIndex();
328 | if (!capture_overlay) {
329 | if (++cur_idx >= data.backbuffer_count)
330 | cur_idx = 0;
331 | }
332 | } else {
333 | cur_idx = data.cur_backbuffer;
334 | }
335 |
336 | ID3D11Resource *backbuffer = data.backbuffer11[cur_idx];
337 |
338 | data.device11on12->AcquireWrappedResources(&backbuffer, 1);
339 | d3d12_copy_texture(data.copy_tex, backbuffer);
340 | data.device11on12->ReleaseWrappedResources(&backbuffer, 1);
341 | data.context11->Flush();
342 |
343 | if (!dxgi_1_4) {
344 | if (++data.cur_backbuffer >= data.backbuffer_count)
345 | data.cur_backbuffer = 0;
346 | }
347 | }
348 |
349 | void d3d12_capture(void *swap_ptr, void *, bool capture_overlay)
350 | {
351 | IDXGISwapChain *swap = (IDXGISwapChain *)swap_ptr;
352 |
353 | if (capture_should_stop()) {
354 | d3d12_free();
355 | }
356 | if (capture_should_init()) {
357 | d3d12_init(swap);
358 | }
359 | if (capture_ready()) {
360 | d3d12_shtex_capture(swap, capture_overlay);
361 | }
362 | }
363 |
364 | #endif
365 |
--------------------------------------------------------------------------------
/NoxCap/gl-subsystem.h:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | Copyright (C) 2013 by Hugh Bailey
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 2 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
16 | ******************************************************************************/
17 |
18 | #pragma once
19 | #include
20 |
21 | struct gl_platform;
22 | struct gl_windowinfo;
23 |
24 | enum copy_type { COPY_TYPE_ARB, COPY_TYPE_NV, COPY_TYPE_FBO_BLIT };
25 |
26 |
27 | #define GS_MAX_TEXTURES 8
28 |
29 |
30 | typedef struct gs_shader gs_shader_t;
31 | typedef struct gs_device gs_device_t;
32 | typedef struct gs_sampler_state gs_samplerstate_t;
33 | typedef struct gs_texture gs_texture_t;
34 | typedef struct gs_zstencil_buffer gs_zstencil_t;
35 | typedef struct gs_vertex_buffer gs_vertbuffer_t;
36 | typedef struct gs_index_buffer gs_indexbuffer_t;
37 | typedef struct gs_swap_chain gs_swapchain_t;
38 |
39 |
40 | typedef unsigned int GLuint;
41 | typedef int GLint;
42 | typedef unsigned int GLenum;
43 |
44 |
45 |
46 | enum gs_texture_type {
47 | GS_TEXTURE_2D,
48 | GS_TEXTURE_3D,
49 | GS_TEXTURE_CUBE,
50 | };
51 |
52 |
53 | enum attrib_type {
54 | ATTRIB_POSITION,
55 | ATTRIB_NORMAL,
56 | ATTRIB_TANGENT,
57 | ATTRIB_COLOR,
58 | ATTRIB_TEXCOORD,
59 | ATTRIB_TARGET
60 | };
61 |
62 | struct shader_attrib {
63 | char *name;
64 | size_t index;
65 | enum attrib_type type;
66 | };
67 |
68 |
69 | #define DARRAY_INVALID ((size_t)-1)
70 | #define DARRAY(type) \
71 | union { \
72 | struct darray da; \
73 | struct { \
74 | type *array; \
75 | size_t num; \
76 | size_t capacity; \
77 | }; \
78 | }
79 |
80 | struct darray {
81 | void *array;
82 | size_t num;
83 | size_t capacity;
84 | };
85 |
86 | struct gs_sampler_state {
87 | gs_device_t *device;
88 | volatile long ref;
89 |
90 | GLint min_filter;
91 | GLint mag_filter;
92 | GLint address_u;
93 | GLint address_v;
94 | GLint address_w;
95 | GLint max_anisotropy;
96 | };
97 |
98 |
99 | struct gs_shader {
100 | gs_device_t *device;
101 | enum gs_shader_type type;
102 | GLuint obj;
103 |
104 | struct gs_shader_param *viewproj;
105 | struct gs_shader_param *world;
106 |
107 | DARRAY(struct shader_attrib) attribs;
108 | DARRAY(struct gs_shader_param) params;
109 | DARRAY(gs_samplerstate_t *) samplers;
110 | };
111 |
112 | enum gs_shader_param_type {
113 | GS_SHADER_PARAM_UNKNOWN,
114 | GS_SHADER_PARAM_BOOL,
115 | GS_SHADER_PARAM_FLOAT,
116 | GS_SHADER_PARAM_INT,
117 | GS_SHADER_PARAM_STRING,
118 | GS_SHADER_PARAM_VEC2,
119 | GS_SHADER_PARAM_VEC3,
120 | GS_SHADER_PARAM_VEC4,
121 | GS_SHADER_PARAM_INT2,
122 | GS_SHADER_PARAM_INT3,
123 | GS_SHADER_PARAM_INT4,
124 | GS_SHADER_PARAM_MATRIX4X4,
125 | GS_SHADER_PARAM_TEXTURE,
126 | };
127 |
128 | struct gs_shader_param {
129 | enum gs_shader_param_type type;
130 |
131 | char *name;
132 | gs_shader_t *shader;
133 | gs_samplerstate_t *next_sampler;
134 | GLint texture_id;
135 | size_t sampler_id;
136 | int array_count;
137 |
138 | struct gs_texture *texture;
139 |
140 | DARRAY(unsigned char) cur_value;
141 | DARRAY(unsigned char) def_value;
142 | BOOL changed;
143 | };
144 |
145 | struct program_param {
146 | GLint obj;
147 | struct gs_shader_param *param;
148 | };
149 |
150 | struct gs_program {
151 | gs_device_t *device;
152 | GLuint obj;
153 | struct gs_shader *vertex_shader;
154 | struct gs_shader *pixel_shader;
155 |
156 | DARRAY(struct program_param) params;
157 | DARRAY(GLint) attribs;
158 |
159 | struct gs_program **prev_next;
160 | struct gs_program *next;
161 | };
162 |
163 | extern struct gs_program *gs_program_create(struct gs_device *device);
164 | extern void gs_program_destroy(struct gs_program *program);
165 | extern void program_update_params(struct gs_program *shader);
166 |
167 | struct gs_vertex_buffer {
168 | GLuint vao;
169 | GLuint vertex_buffer;
170 | GLuint normal_buffer;
171 | GLuint tangent_buffer;
172 | GLuint color_buffer;
173 | DARRAY(GLuint) uv_buffers;
174 | DARRAY(size_t) uv_sizes;
175 |
176 | gs_device_t *device;
177 | size_t num;
178 | BOOL dynamic;
179 | struct gs_vb_data *data;
180 | };
181 |
182 | extern BOOL load_vb_buffers(struct gs_program *program,
183 | struct gs_vertex_buffer *vb,
184 | struct gs_index_buffer *ib);
185 |
186 | struct gs_index_buffer {
187 | GLuint buffer;
188 | enum gs_index_type type;
189 | GLuint gl_type;
190 |
191 | gs_device_t *device;
192 | void *data;
193 | size_t num;
194 | size_t width;
195 | size_t size;
196 | BOOL dynamic;
197 | };
198 |
199 | struct gs_texture {
200 | gs_device_t *device;
201 | enum gs_texture_type type;
202 | enum gs_color_format format;
203 | GLenum gl_format;
204 | GLenum gl_target;
205 | GLenum gl_internal_format;
206 | GLenum gl_type;
207 | GLuint texture;
208 | uint32_t levels;
209 | BOOL is_dynamic;
210 | BOOL is_render_target;
211 | BOOL is_dummy;
212 | BOOL gen_mipmaps;
213 |
214 | gs_samplerstate_t *cur_sampler;
215 | struct fbo_info *fbo;
216 | };
217 |
218 | struct gs_texture_2d {
219 | struct gs_texture base;
220 |
221 | uint32_t width;
222 | uint32_t height;
223 | BOOL gen_mipmaps;
224 | GLuint unpack_buffer;
225 | };
226 |
227 | struct gs_texture_cube {
228 | struct gs_texture base;
229 |
230 | uint32_t size;
231 | };
232 |
233 | struct gs_stage_surface {
234 | gs_device_t *device;
235 |
236 | enum gs_color_format format;
237 | uint32_t width;
238 | uint32_t height;
239 |
240 | uint32_t bytes_per_pixel;
241 | GLenum gl_format;
242 | GLint gl_internal_format;
243 | GLenum gl_type;
244 | GLuint pack_buffer;
245 | };
246 |
247 | struct gs_zstencil_buffer {
248 | gs_device_t *device;
249 | GLuint buffer;
250 | GLuint attachment;
251 | GLenum format;
252 | };
253 |
254 | struct fbo_info {
255 | GLuint fbo;
256 | uint32_t width;
257 | uint32_t height;
258 | enum gs_color_format format;
259 |
260 | gs_texture_t *cur_render_target;
261 | int cur_render_side;
262 | gs_zstencil_t *cur_zstencil_buffer;
263 | };
264 |
265 | struct gs_window {
266 | #if defined(_WIN32)
267 | void *hwnd;
268 | #elif defined(__APPLE__)
269 | __unsafe_unretained id view;
270 | #elif defined(__linux__) || defined(__FreeBSD__)
271 | /* I'm not sure how portable defining id to uint32_t is. */
272 | uint32_t id;
273 | void *display;
274 | #endif
275 | };
276 |
277 | enum gs_color_format {
278 | GS_UNKNOWN,
279 | GS_A8,
280 | GS_R8,
281 | GS_RGBA,
282 | GS_BGRX,
283 | GS_BGRA,
284 | GS_R10G10B10A2,
285 | GS_RGBA16,
286 | GS_R16,
287 | GS_RGBA16F,
288 | GS_RGBA32F,
289 | GS_RG16F,
290 | GS_RG32F,
291 | GS_R16F,
292 | GS_R32F,
293 | GS_DXT1,
294 | GS_DXT3,
295 | GS_DXT5,
296 | GS_R8G8,
297 | };
298 |
299 | enum gs_zstencil_format {
300 | GS_ZS_NONE,
301 | GS_Z16,
302 | GS_Z24_S8,
303 | GS_Z32F,
304 | GS_Z32F_S8X24,
305 | };
306 |
307 |
308 | struct gs_init_data {
309 | struct gs_window window;
310 | uint32_t cx, cy;
311 | uint32_t num_backbuffers;
312 | enum gs_color_format format;
313 | enum gs_zstencil_format zsformat;
314 | uint32_t adapter;
315 | };
316 |
317 | struct gs_swap_chain {
318 | gs_device_t *device;
319 | struct gl_windowinfo *wi;
320 | struct gs_init_data info;
321 | };
322 | struct gs_rect {
323 | int x;
324 | int y;
325 | int cx;
326 | int cy;
327 | };
328 |
329 | typedef union __declspec(intrin_type) __declspec(align(16)) __m128 {
330 | float m128_f32[4];
331 | unsigned __int64 m128_u64[2];
332 | __int8 m128_i8[16];
333 | __int16 m128_i16[8];
334 | __int32 m128_i32[4];
335 | __int64 m128_i64[2];
336 | unsigned __int8 m128_u8[16];
337 | unsigned __int16 m128_u16[8];
338 | unsigned __int32 m128_u32[4];
339 | } __m128;
340 |
341 | struct vec4 {
342 | union {
343 | struct {
344 | float x, y, z, w;
345 | };
346 | float ptr[4];
347 | __m128 m;
348 | };
349 | };
350 |
351 | struct matrix4 {
352 | struct vec4 x, y, z, t;
353 | };
354 |
355 | struct gs_device {
356 | struct gl_platform *plat;
357 | enum copy_type copy_type;
358 |
359 | GLuint empty_vao;
360 |
361 | gs_texture_t *cur_render_target;
362 | gs_zstencil_t *cur_zstencil_buffer;
363 | int cur_render_side;
364 | gs_texture_t *cur_textures[GS_MAX_TEXTURES];
365 | gs_samplerstate_t *cur_samplers[GS_MAX_TEXTURES];
366 | gs_vertbuffer_t *cur_vertex_buffer;
367 | gs_indexbuffer_t *cur_index_buffer;
368 | gs_shader_t *cur_vertex_shader;
369 | gs_shader_t *cur_pixel_shader;
370 | gs_swapchain_t *cur_swap;
371 | struct gs_program *cur_program;
372 |
373 | struct gs_program *first_program;
374 |
375 | enum gs_cull_mode cur_cull_mode;
376 | struct gs_rect cur_viewport;
377 |
378 | struct matrix4 cur_proj;
379 | struct matrix4 cur_view;
380 | struct matrix4 cur_viewproj;
381 |
382 | DARRAY(struct matrix4) proj_stack;
383 |
384 | struct fbo_info *cur_fbo;
385 | };
386 |
387 | extern struct fbo_info *get_fbo(gs_texture_t *tex, uint32_t width,
388 | uint32_t height);
389 |
390 | extern void gl_update(gs_device_t *device);
391 |
392 | extern struct gl_platform *gl_platform_create(gs_device_t *device,
393 | uint32_t adapter);
394 | extern void gl_platform_destroy(struct gl_platform *platform);
395 |
396 | extern BOOL gl_platform_init_swapchain(struct gs_swap_chain *swap);
397 | extern void gl_platform_cleanup_swapchain(struct gs_swap_chain *swap);
398 |
399 | extern struct gl_windowinfo *
400 | gl_windowinfo_create(const struct gs_init_data *info);
401 | extern void gl_windowinfo_destroy(struct gl_windowinfo *wi);
402 |
403 | extern void gl_getclientsize(const struct gs_swap_chain *swap, uint32_t *width,
404 | uint32_t *height);
405 |
--------------------------------------------------------------------------------
/Nox/Noxcap.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Debug
10 | x64
11 |
12 |
13 | Release
14 | Win32
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {5FA3E3CD-46E5-4FF6-B648-73228D99586A}
23 | Win32Proj
24 | Noxcap
25 | Noxcap
26 |
27 |
28 |
29 | DynamicLibrary
30 | true
31 | v120
32 | Unicode
33 |
34 |
35 | DynamicLibrary
36 | true
37 | v120
38 | Unicode
39 |
40 |
41 | DynamicLibrary
42 | false
43 | v120
44 | true
45 | Unicode
46 |
47 |
48 | DynamicLibrary
49 | false
50 | v120
51 | true
52 | Unicode
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | true
72 | $(ProjectName)
73 | $(SolutionDir)$(Configuration)\
74 |
75 |
76 | true
77 | $(ProjectName)
78 |
79 |
80 | false
81 |
82 |
83 | false
84 |
85 |
86 |
87 | NotUsing
88 | Level3
89 | Disabled
90 | _DEBUG;_WINDOWS;_USRDLL;NOXCAP_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
91 | true
92 |
93 |
94 | Windows
95 | true
96 |
97 |
98 | MachineX64
99 |
100 |
101 |
102 |
103 | NotUsing
104 | Level3
105 | Disabled
106 | _DEBUG;_WINDOWS;_USRDLL;NOXCAP_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
107 | true
108 |
109 |
110 | Windows
111 | true
112 |
113 |
114 |
115 |
116 |
117 |
118 | Level3
119 | Use
120 | MaxSpeed
121 | true
122 | true
123 | WIN32;NDEBUG;_WINDOWS;_USRDLL;NOXCAP_EXPORTS;%(PreprocessorDefinitions)
124 | true
125 |
126 |
127 | Windows
128 | true
129 | true
130 | true
131 |
132 |
133 |
134 |
135 | Level3
136 | NotUsing
137 | MaxSpeed
138 | true
139 | true
140 | _WINDOWS;_USRDLL;NOXCAP_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
141 | true
142 |
143 |
144 | Windows
145 | true
146 | true
147 | true
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 | Create
183 | Create
184 | Create
185 | Create
186 |
187 |
188 |
189 |
190 |
191 |
--------------------------------------------------------------------------------
/Nox/graphic-hook/d3d8-capture.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "../d3d8-api/d3d8.h"
4 | #include "graphics-hook.h"
5 | #include "../funchook.h"
6 |
7 | typedef HRESULT(STDMETHODCALLTYPE *reset_t)(IDirect3DDevice8 *,
8 | D3DPRESENT_PARAMETERS *);
9 | typedef HRESULT(STDMETHODCALLTYPE *present_t)(IDirect3DDevice8 *, CONST RECT *,
10 | CONST RECT *, HWND,
11 | CONST RGNDATA *);
12 |
13 | static struct func_hook present;
14 | static struct func_hook reset;
15 |
16 | struct d3d8_data {
17 | HMODULE d3d8;
18 | uint32_t cx;
19 | uint32_t cy;
20 | D3DFORMAT d3d8_format;
21 | DXGI_FORMAT dxgi_format;
22 |
23 | struct shmem_data *shmem_info;
24 | HWND window;
25 | uint32_t pitch;
26 | IDirect3DSurface8 *copy_surfaces[NUM_BUFFERS];
27 | bool surface_locked[NUM_BUFFERS];
28 | int cur_surface;
29 | int copy_wait;
30 | };
31 |
32 | static d3d8_data data = {};
33 |
34 | static DXGI_FORMAT d3d8_to_dxgi_format(D3DFORMAT format)
35 | {
36 | switch ((unsigned long)format) {
37 | case D3DFMT_X1R5G5B5:
38 | case D3DFMT_A1R5G5B5:
39 | return DXGI_FORMAT_B5G5R5A1_UNORM;
40 | case D3DFMT_R5G6B5:
41 | return DXGI_FORMAT_B5G6R5_UNORM;
42 | case D3DFMT_A8R8G8B8:
43 | return DXGI_FORMAT_B8G8R8A8_UNORM;
44 | case D3DFMT_X8R8G8B8:
45 | return DXGI_FORMAT_B8G8R8X8_UNORM;
46 | }
47 |
48 | return DXGI_FORMAT_UNKNOWN;
49 | }
50 |
51 | static IDirect3DSurface8 *d3d8_get_backbuffer(IDirect3DDevice8 *device)
52 | {
53 | IDirect3DSurface8 *backbuffer;
54 | HRESULT hr;
55 |
56 | hr = device->GetRenderTarget(&backbuffer);
57 | if (FAILED(hr)) {
58 | hlog_hr("d3d8_get_backbuffer: Failed to get backbuffer", hr);
59 | backbuffer = nullptr;
60 | }
61 |
62 | return backbuffer;
63 | }
64 |
65 | static bool d3d8_get_window_handle(IDirect3DDevice8 *device)
66 | {
67 | D3DDEVICE_CREATION_PARAMETERS parameters;
68 | HRESULT hr;
69 | hr = device->GetCreationParameters(¶meters);
70 | if (FAILED(hr)) {
71 | hlog_hr("d3d8_get_window_handle: Failed to get "
72 | "device creation parameters",
73 | hr);
74 | return false;
75 | }
76 |
77 | data.window = parameters.hFocusWindow;
78 |
79 | return true;
80 | }
81 |
82 | static bool d3d8_init_format_backbuffer(IDirect3DDevice8 *device)
83 | {
84 | IDirect3DSurface8 *backbuffer;
85 | D3DSURFACE_DESC desc;
86 | HRESULT hr;
87 |
88 | if (!d3d8_get_window_handle(device))
89 | return false;
90 |
91 | backbuffer = d3d8_get_backbuffer(device);
92 | if (!backbuffer)
93 | return false;
94 |
95 | hr = backbuffer->GetDesc(&desc);
96 | backbuffer->Release();
97 | if (FAILED(hr)) {
98 | hlog_hr("d3d8_init_format_backbuffer: Failed to get "
99 | "backbuffer descriptor",
100 | hr);
101 | return false;
102 | }
103 |
104 | data.d3d8_format = desc.Format;
105 | data.dxgi_format = d3d8_to_dxgi_format(desc.Format);
106 | data.cx = desc.Width;
107 | data.cy = desc.Height;
108 |
109 | return true;
110 | }
111 |
112 | static bool d3d8_shmem_init_buffer(IDirect3DDevice8 *device, int idx)
113 | {
114 | HRESULT hr;
115 |
116 | hr = device->CreateImageSurface(data.cx, data.cy, data.d3d8_format,
117 | &data.copy_surfaces[idx]);
118 | if (FAILED(hr)) {
119 | hlog_hr("d3d8_shmem_init_buffer: Failed to create surface", hr);
120 | return false;
121 | }
122 |
123 | if (idx == 0) {
124 | D3DLOCKED_RECT rect;
125 | hr = data.copy_surfaces[0]->LockRect(&rect, nullptr,
126 | D3DLOCK_READONLY);
127 | if (FAILED(hr)) {
128 | hlog_hr("d3d8_shmem_init_buffer: Failed to lock buffer",
129 | hr);
130 | return false;
131 | }
132 |
133 | data.pitch = rect.Pitch;
134 | data.copy_surfaces[0]->UnlockRect();
135 | }
136 |
137 | return true;
138 | }
139 |
140 | static bool d3d8_shmem_init(IDirect3DDevice8 *device)
141 | {
142 | for (int i = 0; i < NUM_BUFFERS; i++) {
143 | if (!d3d8_shmem_init_buffer(device, i)) {
144 | return false;
145 | }
146 | }
147 | if (!capture_init_shmem(&data.shmem_info, data.window, data.cx, data.cy,
148 | data.cx, data.cy, data.pitch, data.dxgi_format,
149 | false)) {
150 | return false;
151 | }
152 |
153 | hlog("d3d8 memory capture successful");
154 | return true;
155 | }
156 |
157 | static void d3d8_free()
158 | {
159 | capture_free();
160 |
161 | for (size_t i = 0; i < NUM_BUFFERS; i++) {
162 | if (data.copy_surfaces[i]) {
163 | if (data.surface_locked[i])
164 | data.copy_surfaces[i]->UnlockRect();
165 | data.copy_surfaces[i]->Release();
166 | }
167 | }
168 |
169 | memset(&data, 0, sizeof(data));
170 |
171 | hlog("----------------- d3d8 capture freed -----------------");
172 | }
173 |
174 | static void d3d8_init(IDirect3DDevice8 *device)
175 | {
176 | data.d3d8 = get_system_module("d3d8.dll");
177 |
178 | if (!d3d8_init_format_backbuffer(device))
179 | return;
180 |
181 | if (!d3d8_shmem_init(device))
182 | d3d8_free();
183 | }
184 |
185 | static void d3d8_shmem_capture_copy(int idx)
186 | {
187 | IDirect3DSurface8 *target = data.copy_surfaces[idx];
188 | D3DLOCKED_RECT rect;
189 | HRESULT hr;
190 |
191 | if (data.surface_locked[idx])
192 | return;
193 |
194 | hr = target->LockRect(&rect, nullptr, D3DLOCK_READONLY);
195 | if (SUCCEEDED(hr)) {
196 | shmem_copy_data(idx, rect.pBits);
197 | }
198 | }
199 |
200 | static void d3d8_shmem_capture(IDirect3DDevice8 *device,
201 | IDirect3DSurface8 *backbuffer)
202 | {
203 | int cur_surface;
204 | int next_surface;
205 | HRESULT hr;
206 |
207 | cur_surface = data.cur_surface;
208 | next_surface = (cur_surface == NUM_BUFFERS - 1) ? 0 : cur_surface + 1;
209 |
210 | if (data.copy_wait < NUM_BUFFERS - 1) {
211 | data.copy_wait++;
212 | } else {
213 | IDirect3DSurface8 *src = backbuffer;
214 | IDirect3DSurface8 *dst = data.copy_surfaces[cur_surface];
215 |
216 | if (shmem_texture_data_lock(next_surface)) {
217 | dst->UnlockRect();
218 | data.surface_locked[next_surface] = false;
219 | shmem_texture_data_unlock(next_surface);
220 | }
221 |
222 | hr = device->CopyRects(src, nullptr, 0, dst, nullptr);
223 | if (SUCCEEDED(hr)) {
224 | d3d8_shmem_capture_copy(cur_surface);
225 | }
226 | }
227 |
228 | data.cur_surface = next_surface;
229 | }
230 |
231 | static void d3d8_capture(IDirect3DDevice8 *device,
232 | IDirect3DSurface8 *backbuffer)
233 | {
234 | if (capture_should_stop()) {
235 | d3d8_free();
236 | }
237 | if (capture_should_init()) {
238 | d3d8_init(device);
239 | }
240 | if (capture_ready()) {
241 | d3d8_shmem_capture(device, backbuffer);
242 | }
243 | }
244 |
245 | static HRESULT STDMETHODCALLTYPE hook_reset(IDirect3DDevice8 *device,
246 | D3DPRESENT_PARAMETERS *parameters)
247 | {
248 | HRESULT hr;
249 |
250 | if (capture_active())
251 | d3d8_free();
252 |
253 | unhook(&reset);
254 | reset_t call = (reset_t)reset.call_addr;
255 | hr = call(device, parameters);
256 | rehook(&reset);
257 |
258 | return hr;
259 | }
260 |
261 | static bool hooked_reset = false;
262 |
263 | static void setup_reset_hooks(IDirect3DDevice8 *device)
264 | {
265 | uintptr_t *vtable = *(uintptr_t **)device;
266 |
267 | hook_init(&reset, (void *)vtable[14], (void *)hook_reset,
268 | "IDirect3DDevice8::Reset");
269 | rehook(&reset);
270 |
271 | hooked_reset = true;
272 | }
273 |
274 | static HRESULT STDMETHODCALLTYPE hook_present(IDirect3DDevice8 *device,
275 | CONST RECT *src_rect,
276 | CONST RECT *dst_rect,
277 | HWND override_window,
278 | CONST RGNDATA *dirty_region)
279 | {
280 | IDirect3DSurface8 *backbuffer;
281 | HRESULT hr;
282 |
283 | if (!hooked_reset)
284 | setup_reset_hooks(device);
285 |
286 | backbuffer = d3d8_get_backbuffer(device);
287 | if (backbuffer) {
288 | d3d8_capture(device, backbuffer);
289 | backbuffer->Release();
290 | }
291 |
292 | unhook(&present);
293 | present_t call = (present_t)present.call_addr;
294 | hr = call(device, src_rect, dst_rect, override_window, dirty_region);
295 | rehook(&present);
296 |
297 | return hr;
298 | }
299 |
300 | typedef IDirect3D8 *(WINAPI *d3d8create_t)(UINT);
301 |
302 | static bool manually_get_d3d8_present_addr(HMODULE d3d8_module,
303 | void **present_addr)
304 | {
305 | d3d8create_t create;
306 | D3DPRESENT_PARAMETERS pp;
307 | HRESULT hr;
308 |
309 | IDirect3DDevice8 *device;
310 | IDirect3D8 *d3d8;
311 |
312 | hlog("D3D8 value invalid, manually obtaining");
313 |
314 | create = (d3d8create_t)GetProcAddress(d3d8_module, "Direct3DCreate8");
315 | if (!create) {
316 | hlog("Failed to load Direct3DCreate8");
317 | return false;
318 | }
319 |
320 | d3d8 = create(D3D_SDK_VERSION);
321 | if (!d3d8) {
322 | hlog("Failed to create D3D8 context");
323 | return false;
324 | }
325 |
326 | memset(&pp, 0, sizeof(pp));
327 | pp.Windowed = true;
328 | pp.SwapEffect = D3DSWAPEFFECT_FLIP;
329 | pp.BackBufferFormat = D3DFMT_A8R8G8B8;
330 | pp.BackBufferWidth = 2;
331 | pp.BackBufferHeight = 2;
332 | pp.BackBufferCount = 1;
333 | pp.hDeviceWindow = dummy_window;
334 |
335 | hr = d3d8->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
336 | dummy_window,
337 | D3DCREATE_HARDWARE_VERTEXPROCESSING, &pp,
338 | &device);
339 | d3d8->Release();
340 |
341 | if (SUCCEEDED(hr)) {
342 | uintptr_t *vtable = *(uintptr_t **)device;
343 | *present_addr = (void *)vtable[15];
344 |
345 | device->Release();
346 | } else {
347 | hlog("Failed to create D3D8 device");
348 | return false;
349 | }
350 |
351 | return true;
352 | }
353 |
354 | bool hook_d3d8(void)
355 | {
356 | HMODULE d3d8_module = get_system_module("d3d8.dll");
357 | void *present_addr = nullptr;
358 |
359 | if (!d3d8_module) {
360 | return false;
361 | }
362 | if (!manually_get_d3d8_present_addr(d3d8_module,
363 | &present_addr)) {
364 | hlog("Failed to get D3D8 value");
365 | return true;
366 | }
367 | /*
368 | d3d8_size = module_size(d3d8_module);
369 |
370 | if (global_hook_info->offsets.d3d8.present < d3d8_size) {
371 | present_addr = get_offset_addr(
372 | d3d8_module, global_hook_info->offsets.d3d8.present);
373 | } else {
374 | if (!dummy_window) {
375 | return false;
376 | }
377 |
378 | if (!manually_get_d3d8_present_addr(d3d8_module,
379 | &present_addr)) {
380 | hlog("Failed to get D3D8 value");
381 | return true;
382 | }
383 | }
384 | */
385 | if (!present_addr) {
386 | hlog("Invalid D3D8 value");
387 | return true;
388 | }
389 |
390 | hook_init(&present, present_addr, (void *)hook_present,
391 | "IDirect3DDevice8::Present");
392 |
393 | rehook(&present);
394 |
395 | hlog("Hooked D3D8");
396 | return true;
397 | }
398 |
--------------------------------------------------------------------------------