mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-14 02:31:12 +00:00
2029 lines
102 KiB
C++
2029 lines
102 KiB
C++
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2015-2018 Baldur Karlsson
|
|
* Copyright (c) 2014 Crytek
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
******************************************************************************/
|
|
|
|
#include "common/threading.h"
|
|
#include "driver/gl/gl_common.h"
|
|
#include "driver/gl/gl_driver.h"
|
|
#include "driver/gl/gl_hookset.h"
|
|
#include "driver/gl/gl_hookset_defs.h"
|
|
#include "hooks/hooks.h"
|
|
#include "strings/string_utils.h"
|
|
|
|
#define DLL_NAME "opengl32.dll"
|
|
|
|
#define HookInit(function) \
|
|
bool CONCAT(function, _success) = \
|
|
CONCAT(function, _hook).Initialize(STRINGIZE(function), DLL_NAME, CONCAT(function, _hooked)); \
|
|
if(!CONCAT(function, _success)) \
|
|
RDCWARN("Couldn't hook %s", STRINGIZE(function)); \
|
|
success &= CONCAT(function, _success); \
|
|
GL.function = CONCAT(function, _hook)();
|
|
|
|
#define HookExtension(funcPtrType, function) \
|
|
if(!strcmp(func, STRINGIZE(function))) \
|
|
{ \
|
|
if(glhooks.GL.function == NULL) \
|
|
glhooks.GL.function = (funcPtrType)realFunc; \
|
|
return (PROC)&glhooks.CONCAT(function, _hooked); \
|
|
}
|
|
|
|
#define HookExtensionAlias(funcPtrType, function, alias) \
|
|
if(!strcmp(func, STRINGIZE(alias))) \
|
|
{ \
|
|
if(glhooks.GL.function == NULL) \
|
|
glhooks.GL.function = (funcPtrType)realFunc; \
|
|
return (PROC)&glhooks.CONCAT(alias, _hooked); \
|
|
}
|
|
|
|
#if 0 // debug print for each unsupported function requested (but not used)
|
|
#define HandleUnsupported(funcPtrType, function) \
|
|
if(!strcmp(func, STRINGIZE(function))) \
|
|
{ \
|
|
glhooks.CONCAT(unsupported_real_, function) = (CONCAT(function, _hooktype))realFunc; \
|
|
RDCDEBUG("Requesting function pointer for unsupported function " STRINGIZE(function)); \
|
|
return (PROC)&glhooks.CONCAT(function, _hooked); \
|
|
}
|
|
#else
|
|
#define HandleUnsupported(funcPtrType, function) \
|
|
if(!strcmp(func, STRINGIZE(function))) \
|
|
{ \
|
|
glhooks.CONCAT(unsupported_real_, function) = (CONCAT(function, _hooktype))realFunc; \
|
|
return (PROC)&glhooks.CONCAT(function, _hooked); \
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
in bash:
|
|
|
|
function WrapperMacro()
|
|
{
|
|
NAME=$1;
|
|
N=$2;
|
|
ALIAS=$3;
|
|
if [ $ALIAS -eq 1 ]; then
|
|
echo -n "#define $NAME$N(ret, function, realfunc";
|
|
else
|
|
echo -n "#define $NAME$N(ret, function";
|
|
fi
|
|
for I in `seq 1 $N`; do echo -n ", t$I, p$I"; done;
|
|
echo ") \\";
|
|
|
|
echo -en " Hook<ret(WINAPI *)(";
|
|
for I in `seq 1 $N`; do echo -n "t$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done;
|
|
echo ")> CONCAT(function, _hook); \\";
|
|
|
|
echo -en " typedef ret(WINAPI *CONCAT(function, _hooktype)) (";
|
|
for I in `seq 1 $N`; do echo -n "t$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done;
|
|
echo "); \\";
|
|
|
|
echo -en " static ret WINAPI CONCAT(function, _hooked)(";
|
|
for I in `seq 1 $N`; do echo -n "t$I p$I"; if [ $I -ne $N ]; then echo -n ", "; fi;
|
|
done;
|
|
echo ") \\";
|
|
|
|
echo -e " { \\";
|
|
echo -e " SCOPED_LOCK(glLock); \\";
|
|
echo -e ' if(!glhooks.m_HaveContextCreation) \\';
|
|
if [ $ALIAS -eq 1 ]; then
|
|
echo -n " return glhooks.GL.realfunc(";
|
|
else
|
|
echo -n " return glhooks.GL.function(";
|
|
fi
|
|
for I in `seq 1 $N`; do echo -n "p$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done;
|
|
echo -e "); \\";
|
|
echo -e " gl_CurChunk = GLChunk::function; \\";
|
|
if [ $ALIAS -eq 1 ]; then
|
|
echo -n " return glhooks.GetDriver()->realfunc(";
|
|
else
|
|
echo -n " return glhooks.GetDriver()->function(";
|
|
fi
|
|
for I in `seq 1 $N`; do echo -n "p$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done;
|
|
echo -e "); \\";
|
|
echo -e " }";
|
|
}
|
|
|
|
for I in `seq 0 17`; do WrapperMacro HookWrapper $I 0; echo; done
|
|
for I in `seq 0 17`; do WrapperMacro HookAliasWrapper $I 1; echo; done
|
|
|
|
*/
|
|
|
|
// don't want these definitions, the only place we'll use these is as parameter/variable names
|
|
#ifdef near
|
|
#undef near
|
|
#endif
|
|
|
|
#ifdef far
|
|
#undef far
|
|
#endif
|
|
|
|
#define HookWrapper0(ret, function) \
|
|
Hook<ret(WINAPI *)()> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(); \
|
|
static ret WINAPI CONCAT(function, _hooked)() \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(); \
|
|
}
|
|
|
|
#define HookWrapper1(ret, function, t1, p1) \
|
|
Hook<ret(WINAPI *)(t1)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(p1); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(p1); \
|
|
}
|
|
|
|
#define HookWrapper2(ret, function, t1, p1, t2, p2) \
|
|
Hook<ret(WINAPI *)(t1, t2)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(p1, p2); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(p1, p2); \
|
|
}
|
|
|
|
#define HookWrapper3(ret, function, t1, p1, t2, p2, t3, p3) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(p1, p2, p3); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(p1, p2, p3); \
|
|
}
|
|
|
|
#define HookWrapper4(ret, function, t1, p1, t2, p2, t3, p3, t4, p4) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(p1, p2, p3, p4); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(p1, p2, p3, p4); \
|
|
}
|
|
|
|
#define HookWrapper5(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(p1, p2, p3, p4, p5); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5); \
|
|
}
|
|
|
|
#define HookWrapper6(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(p1, p2, p3, p4, p5, p6); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6); \
|
|
}
|
|
|
|
#define HookWrapper7(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(p1, p2, p3, p4, p5, p6, p7); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7); \
|
|
}
|
|
|
|
#define HookWrapper8(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(p1, p2, p3, p4, p5, p6, p7, p8); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8); \
|
|
}
|
|
|
|
#define HookWrapper9(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9); \
|
|
}
|
|
|
|
#define HookWrapper10(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
|
|
}
|
|
|
|
#define HookWrapper11(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \
|
|
}
|
|
|
|
#define HookWrapper12(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
|
|
}
|
|
|
|
#define HookWrapper13(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13)> CONCAT(function, \
|
|
_hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12, t13); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \
|
|
}
|
|
|
|
#define HookWrapper14(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14)> CONCAT( \
|
|
function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12, t13, t14); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
|
|
t14 p14) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
|
|
p14); \
|
|
}
|
|
|
|
#define HookWrapper15(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15)> CONCAT( \
|
|
function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12, t13, t14, t15); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
|
|
t14 p14, t15 p15) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
|
|
p14, p15); \
|
|
}
|
|
|
|
#define HookWrapper16(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15, t16, \
|
|
p16) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16)> CONCAT( \
|
|
function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12, t13, t14, t15, t16); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
|
|
t14 p14, t15 p15, t16 p16) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, \
|
|
p16); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
|
|
p14, p15, p16); \
|
|
}
|
|
|
|
#define HookWrapper17(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15, t16, \
|
|
p16, t17, p17) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17)> CONCAT( \
|
|
function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12, t13, t14, t15, t16, t17); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
|
|
t14 p14, t15 p15, t16 p16, t17 p17) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, \
|
|
p16, p17); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
|
|
p14, p15, p16, p17); \
|
|
}
|
|
|
|
#define HookAliasWrapper0(ret, function, realfunc) \
|
|
Hook<ret(WINAPI *)()> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(); \
|
|
static ret WINAPI CONCAT(function, _hooked)() \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(); \
|
|
}
|
|
|
|
#define HookAliasWrapper1(ret, function, realfunc, t1, p1) \
|
|
Hook<ret(WINAPI *)(t1)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(p1); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(p1); \
|
|
}
|
|
|
|
#define HookAliasWrapper2(ret, function, realfunc, t1, p1, t2, p2) \
|
|
Hook<ret(WINAPI *)(t1, t2)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(p1, p2); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(p1, p2); \
|
|
}
|
|
|
|
#define HookAliasWrapper3(ret, function, realfunc, t1, p1, t2, p2, t3, p3) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(p1, p2, p3); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(p1, p2, p3); \
|
|
}
|
|
|
|
#define HookAliasWrapper4(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(p1, p2, p3, p4); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4); \
|
|
}
|
|
|
|
#define HookAliasWrapper5(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(p1, p2, p3, p4, p5); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5); \
|
|
}
|
|
|
|
#define HookAliasWrapper6(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(p1, p2, p3, p4, p5, p6); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6); \
|
|
}
|
|
|
|
#define HookAliasWrapper7(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, \
|
|
t7, p7) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(p1, p2, p3, p4, p5, p6, p7); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7); \
|
|
}
|
|
|
|
#define HookAliasWrapper8(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, \
|
|
t7, p7, t8, p8) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8); \
|
|
}
|
|
|
|
#define HookAliasWrapper9(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, \
|
|
t7, p7, t8, p8, t9, p9) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9); \
|
|
}
|
|
|
|
#define HookAliasWrapper10(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
|
|
p6, t7, p7, t8, p8, t9, p9, t10, p10) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
|
|
}
|
|
|
|
#define HookAliasWrapper11(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
|
|
p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \
|
|
}
|
|
|
|
#define HookAliasWrapper12(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
|
|
p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12)> CONCAT(function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
|
|
}
|
|
|
|
#define HookAliasWrapper13(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
|
|
p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13)> CONCAT(function, \
|
|
_hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12, t13); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \
|
|
}
|
|
|
|
#define HookAliasWrapper14(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
|
|
p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, \
|
|
t14, p14) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14)> CONCAT( \
|
|
function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12, t13, t14); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
|
|
t14 p14) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
|
|
p14); \
|
|
}
|
|
|
|
#define HookAliasWrapper15(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
|
|
p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, \
|
|
t14, p14, t15, p15) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15)> CONCAT( \
|
|
function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12, t13, t14, t15); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
|
|
t14 p14, t15 p15) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
|
|
p14, p15); \
|
|
}
|
|
|
|
#define HookAliasWrapper16(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
|
|
p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, \
|
|
t14, p14, t15, p15, t16, p16) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16)> CONCAT( \
|
|
function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12, t13, t14, t15, t16); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
|
|
t14 p14, t15 p15, t16 p16) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, \
|
|
p16); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
|
|
p14, p15, p16); \
|
|
}
|
|
|
|
#define HookAliasWrapper17(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \
|
|
p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, \
|
|
t14, p14, t15, p15, t16, p16, t17, p17) \
|
|
Hook<ret(WINAPI *)(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17)> CONCAT( \
|
|
function, _hook); \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12, t13, t14, t15, t16, t17); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
|
|
t14 p14, t15 p15, t16 p16, t17 p17) \
|
|
{ \
|
|
SCOPED_LOCK(glLock); \
|
|
if(!glhooks.m_HaveContextCreation) \
|
|
return glhooks.GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, \
|
|
p16, p17); \
|
|
gl_CurChunk = GLChunk::function; \
|
|
return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \
|
|
p14, p15, p16, p17); \
|
|
}
|
|
|
|
Threading::CriticalSection glLock;
|
|
|
|
typedef BOOL(WINAPI *WGLMAKECURRENTPROC)(HDC, HGLRC);
|
|
typedef BOOL(WINAPI *WGLDELETECONTEXTPROC)(HGLRC);
|
|
|
|
extern PFNWGLCREATECONTEXTATTRIBSARBPROC createContextAttribs;
|
|
extern PFNWGLGETPIXELFORMATATTRIBIVARBPROC getPixelFormatAttrib;
|
|
extern WGLMAKECURRENTPROC wglMakeCurrentProc;
|
|
extern WGLDELETECONTEXTPROC wglDeleteRC;
|
|
|
|
class OpenGLHook : LibraryHook, public GLPlatform
|
|
{
|
|
public:
|
|
OpenGLHook()
|
|
{
|
|
LibraryHooks::GetInstance().RegisterHook(DLL_NAME, this);
|
|
|
|
m_GLDriver = NULL;
|
|
|
|
m_HasHooks = false;
|
|
|
|
m_HaveContextCreation = false;
|
|
|
|
m_EnabledHooks = true;
|
|
m_PopulatedHooks = false;
|
|
|
|
m_CreatingContext = false;
|
|
|
|
SetUnsupportedFunctionPointersToNULL();
|
|
}
|
|
~OpenGLHook() { delete m_GLDriver; }
|
|
bool CreateHooks(const char *libName)
|
|
{
|
|
RDCEraseEl(GL);
|
|
|
|
if(!m_EnabledHooks)
|
|
return false;
|
|
|
|
bool success = SetupHooks();
|
|
|
|
if(!success)
|
|
return false;
|
|
|
|
m_HasHooks = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
void EnableHooks(const char *libName, bool enable) { m_EnabledHooks = enable; }
|
|
void OptionsUpdated(const char *libName) {}
|
|
static OpenGLHook glhooks;
|
|
|
|
const GLHookSet &GetRealGLFunctions()
|
|
{
|
|
if(!m_PopulatedHooks)
|
|
m_PopulatedHooks = PopulateHooks();
|
|
return GL;
|
|
}
|
|
|
|
void MakeContextCurrent(GLWindowingData data)
|
|
{
|
|
if(wglMakeCurrent_hook())
|
|
wglMakeCurrent_hook()(data.DC, data.ctx);
|
|
else if(wglMakeCurrentProc)
|
|
wglMakeCurrentProc(data.DC, data.ctx);
|
|
}
|
|
|
|
GLWindowingData MakeContext(GLWindowingData share)
|
|
{
|
|
GLWindowingData ret;
|
|
if(wglCreateContextAttribsARB_realfunc)
|
|
{
|
|
const int attribs[] = {
|
|
WGL_CONTEXT_MAJOR_VERSION_ARB,
|
|
3,
|
|
WGL_CONTEXT_MINOR_VERSION_ARB,
|
|
2,
|
|
WGL_CONTEXT_FLAGS_ARB,
|
|
0,
|
|
WGL_CONTEXT_PROFILE_MASK_ARB,
|
|
WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
|
|
0,
|
|
0,
|
|
};
|
|
ret.DC = share.DC;
|
|
m_CreatingContext = true;
|
|
ret.ctx = wglCreateContextAttribsARB_realfunc(share.DC, share.ctx, attribs);
|
|
m_CreatingContext = false;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void DeleteContext(GLWindowingData context)
|
|
{
|
|
if(context.ctx && wglDeleteContext_hook())
|
|
wglDeleteContext_hook()(context.ctx);
|
|
}
|
|
|
|
void DeleteReplayContext(GLWindowingData context)
|
|
{
|
|
if(wglDeleteRC)
|
|
{
|
|
wglMakeCurrentProc(NULL, NULL);
|
|
wglDeleteRC(context.ctx);
|
|
ReleaseDC(context.wnd, context.DC);
|
|
::DestroyWindow(context.wnd);
|
|
}
|
|
}
|
|
|
|
void SwapBuffers(GLWindowingData context) { ::SwapBuffers(context.DC); }
|
|
void GetOutputWindowDimensions(GLWindowingData context, int32_t &w, int32_t &h)
|
|
{
|
|
RECT rect = {0};
|
|
GetClientRect(context.wnd, &rect);
|
|
w = rect.right - rect.left;
|
|
h = rect.bottom - rect.top;
|
|
}
|
|
|
|
bool IsOutputWindowVisible(GLWindowingData context)
|
|
{
|
|
return (IsWindowVisible(context.wnd) == TRUE);
|
|
}
|
|
|
|
GLWindowingData GLPlatform::MakeOutputWindow(WindowingData window, bool depth,
|
|
GLWindowingData share_context)
|
|
{
|
|
GLWindowingData ret;
|
|
|
|
RDCASSERT(window.system == WindowingSystem::Win32 || window.system == WindowingSystem::Unknown,
|
|
window.system);
|
|
|
|
HWND w = window.win32.window;
|
|
|
|
if(w == NULL)
|
|
w = CreateWindowEx(WS_EX_CLIENTEDGE, L"renderdocGLclass", L"", WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,
|
|
GetModuleHandle(NULL), NULL);
|
|
|
|
HDC DC = GetDC(w);
|
|
|
|
PIXELFORMATDESCRIPTOR pfd = {0};
|
|
|
|
int attrib = eWGL_NUMBER_PIXEL_FORMATS_ARB;
|
|
int value = 1;
|
|
|
|
getPixelFormatAttrib(DC, 1, 0, 1, &attrib, &value);
|
|
|
|
int pf = 0;
|
|
|
|
int numpfs = value;
|
|
for(int i = 1; i <= numpfs; i++)
|
|
{
|
|
// verify that we have the properties we want
|
|
attrib = eWGL_DRAW_TO_WINDOW_ARB;
|
|
getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value);
|
|
if(value == 0)
|
|
continue;
|
|
|
|
attrib = eWGL_ACCELERATION_ARB;
|
|
getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value);
|
|
if(value == eWGL_NO_ACCELERATION_ARB)
|
|
continue;
|
|
|
|
attrib = eWGL_SUPPORT_OPENGL_ARB;
|
|
getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value);
|
|
if(value == 0)
|
|
continue;
|
|
|
|
attrib = eWGL_DOUBLE_BUFFER_ARB;
|
|
getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value);
|
|
if(value == 0)
|
|
continue;
|
|
|
|
attrib = eWGL_PIXEL_TYPE_ARB;
|
|
getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value);
|
|
if(value != eWGL_TYPE_RGBA_ARB)
|
|
continue;
|
|
|
|
// we have an opengl-capable accelerated RGBA context.
|
|
// we use internal framebuffers to do almost all rendering, so we just need
|
|
// RGB (color bits > 24) and SRGB buffer.
|
|
|
|
attrib = eWGL_COLOR_BITS_ARB;
|
|
getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value);
|
|
if(value < 24)
|
|
continue;
|
|
|
|
attrib = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
|
|
getPixelFormatAttrib(DC, i, 0, 1, &attrib, &value);
|
|
if(value == 0)
|
|
continue;
|
|
|
|
// this one suits our needs, choose it
|
|
pf = i;
|
|
break;
|
|
}
|
|
|
|
if(pf == 0)
|
|
{
|
|
ReleaseDC(w, DC);
|
|
RDCERR("Couldn't choose pixel format");
|
|
return ret;
|
|
}
|
|
|
|
BOOL res = DescribePixelFormat(DC, pf, sizeof(pfd), &pfd);
|
|
if(res == FALSE)
|
|
{
|
|
ReleaseDC(w, DC);
|
|
RDCERR("Couldn't describe pixel format");
|
|
return ret;
|
|
}
|
|
|
|
res = SetPixelFormat(DC, pf, &pfd);
|
|
if(res == FALSE)
|
|
{
|
|
ReleaseDC(w, DC);
|
|
RDCERR("Couldn't set pixel format");
|
|
return ret;
|
|
}
|
|
|
|
int attribs[64] = {0};
|
|
int i = 0;
|
|
|
|
attribs[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
|
|
attribs[i++] = GLCoreVersion / 10;
|
|
attribs[i++] = WGL_CONTEXT_MINOR_VERSION_ARB;
|
|
attribs[i++] = GLCoreVersion % 10;
|
|
attribs[i++] = WGL_CONTEXT_FLAGS_ARB;
|
|
#if ENABLED(RDOC_DEVEL)
|
|
attribs[i++] = WGL_CONTEXT_DEBUG_BIT_ARB;
|
|
#else
|
|
attribs[i++] = 0;
|
|
#endif
|
|
attribs[i++] = WGL_CONTEXT_PROFILE_MASK_ARB;
|
|
attribs[i++] = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
|
|
|
|
HGLRC rc = createContextAttribs(DC, share_context.ctx, attribs);
|
|
if(rc == NULL)
|
|
{
|
|
ReleaseDC(w, DC);
|
|
RDCERR("Couldn't create %d.%d context - something changed since creation", GLCoreVersion / 10,
|
|
GLCoreVersion % 10);
|
|
return ret;
|
|
}
|
|
|
|
ret.DC = DC;
|
|
ret.ctx = rc;
|
|
ret.wnd = w;
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool DrawQuads(float width, float height, const std::vector<Vec4f> &vertices);
|
|
|
|
private:
|
|
WrappedOpenGL *GetDriver()
|
|
{
|
|
if(m_GLDriver == NULL)
|
|
m_GLDriver = new WrappedOpenGL(GL, *this);
|
|
|
|
return m_GLDriver;
|
|
}
|
|
|
|
// we use this to check if we've seen a context be created.
|
|
// If we HAVEN'T then RenderDoc was probably injected after
|
|
// the start of the application so we should not call our
|
|
// hooked functions - things will go wrong like missing
|
|
// context data, references to resources we don't know about
|
|
// and hooked functions via wglGetProcAddress being NULL
|
|
// and never being called by the app.
|
|
bool m_HaveContextCreation;
|
|
|
|
Hook<HGLRC(WINAPI *)(HDC)> wglCreateContext_hook;
|
|
Hook<BOOL(WINAPI *)(HGLRC)> wglDeleteContext_hook;
|
|
Hook<HGLRC(WINAPI *)(HDC, int)> wglCreateLayerContext_hook;
|
|
Hook<BOOL(WINAPI *)(HDC, HGLRC)> wglMakeCurrent_hook;
|
|
Hook<PROC(WINAPI *)(const char *)> wglGetProcAddress_hook;
|
|
Hook<BOOL(WINAPI *)(HDC)> SwapBuffers_hook;
|
|
Hook<BOOL(WINAPI *)(HDC)> wglSwapBuffers_hook;
|
|
Hook<BOOL(WINAPI *)(HDC, UINT)> wglSwapLayerBuffers_hook;
|
|
Hook<BOOL(WINAPI *)(UINT, CONST WGLSWAP *)> wglSwapMultipleBuffers_hook;
|
|
Hook<LONG(WINAPI *)(DEVMODEA *, DWORD)> ChangeDisplaySettingsA_hook;
|
|
Hook<LONG(WINAPI *)(DEVMODEW *, DWORD)> ChangeDisplaySettingsW_hook;
|
|
Hook<LONG(WINAPI *)(LPCSTR, DEVMODEA *, HWND, DWORD, LPVOID)> ChangeDisplaySettingsExA_hook;
|
|
Hook<LONG(WINAPI *)(LPCWSTR, DEVMODEW *, HWND, DWORD, LPVOID)> ChangeDisplaySettingsExW_hook;
|
|
|
|
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB_realfunc;
|
|
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB_realfunc;
|
|
PFNWGLGETPIXELFORMATATTRIBFVARBPROC wglGetPixelFormatAttribfvARB_realfunc;
|
|
PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB_realfunc;
|
|
|
|
static GLInitParams GetInitParamsForDC(HDC dc)
|
|
{
|
|
GLInitParams ret;
|
|
|
|
int pf = GetPixelFormat(dc);
|
|
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
DescribePixelFormat(dc, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
|
|
|
|
HWND w = WindowFromDC(dc);
|
|
|
|
RECT r;
|
|
GetClientRect(w, &r);
|
|
|
|
RDCLOG("dc %p. PFD: type %d, %d color bits, %d depth bits, %d stencil bits. Win: %dx%d", dc,
|
|
pfd.iPixelType, pfd.cColorBits, pfd.cDepthBits, pfd.cStencilBits, r.right - r.left,
|
|
r.bottom - r.top);
|
|
|
|
ret.colorBits = pfd.cColorBits;
|
|
ret.depthBits = pfd.cDepthBits;
|
|
ret.stencilBits = pfd.cStencilBits;
|
|
ret.width = (r.right - r.left);
|
|
ret.height = (r.bottom - r.top);
|
|
|
|
ret.isSRGB = true;
|
|
|
|
if(glhooks.wglGetProcAddress_hook() == NULL)
|
|
glhooks.wglGetProcAddress_hook.SetFuncPtr(
|
|
Process::GetFunctionAddress(DLL_NAME, "wglGetProcAddress"));
|
|
|
|
if(glhooks.wglGetPixelFormatAttribivARB_realfunc == NULL)
|
|
glhooks.wglGetProcAddress_hook()("wglGetPixelFormatAttribivARB");
|
|
|
|
if(glhooks.wglGetPixelFormatAttribivARB_realfunc)
|
|
{
|
|
int attrname = eWGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
|
|
int srgb = 1;
|
|
glhooks.wglGetPixelFormatAttribivARB_realfunc(dc, pf, 0, 1, &attrname, &srgb);
|
|
ret.isSRGB = srgb;
|
|
|
|
attrname = eWGL_SAMPLES_ARB;
|
|
int ms = 1;
|
|
glhooks.wglGetPixelFormatAttribivARB_realfunc(dc, pf, 0, 1, &attrname, &ms);
|
|
ret.multiSamples = RDCMAX(1, ms);
|
|
}
|
|
|
|
if(pfd.iPixelType != PFD_TYPE_RGBA)
|
|
{
|
|
RDCERR("Unsupported OpenGL pixel type");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool m_CreatingContext;
|
|
|
|
static HGLRC WINAPI wglCreateContext_hooked(HDC dc)
|
|
{
|
|
HGLRC ret = glhooks.wglCreateContext_hook()(dc);
|
|
|
|
DWORD err = GetLastError();
|
|
|
|
// don't recurse and don't continue if creation failed
|
|
if(glhooks.m_CreatingContext || ret == NULL)
|
|
return ret;
|
|
|
|
glhooks.m_CreatingContext = true;
|
|
|
|
GLWindowingData data;
|
|
data.DC = dc;
|
|
data.wnd = WindowFromDC(dc);
|
|
data.ctx = ret;
|
|
|
|
glhooks.GetDriver()->CreateContext(data, NULL, GetInitParamsForDC(dc), false, false);
|
|
|
|
glhooks.m_HaveContextCreation = true;
|
|
|
|
SetLastError(err);
|
|
|
|
glhooks.m_CreatingContext = false;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static BOOL WINAPI wglDeleteContext_hooked(HGLRC rc)
|
|
{
|
|
if(glhooks.m_HaveContextCreation)
|
|
glhooks.GetDriver()->DeleteContext(rc);
|
|
|
|
SetLastError(0);
|
|
|
|
return glhooks.wglDeleteContext_hook()(rc);
|
|
}
|
|
|
|
static HGLRC WINAPI wglCreateLayerContext_hooked(HDC dc, int iLayerPlane)
|
|
{
|
|
HGLRC ret = glhooks.wglCreateLayerContext_hook()(dc, iLayerPlane);
|
|
|
|
DWORD err = GetLastError();
|
|
|
|
// don't recurse and don't continue if creation failed
|
|
if(glhooks.m_CreatingContext || ret == NULL)
|
|
return ret;
|
|
|
|
glhooks.m_CreatingContext = true;
|
|
|
|
GLWindowingData data;
|
|
data.DC = dc;
|
|
data.wnd = WindowFromDC(dc);
|
|
data.ctx = ret;
|
|
|
|
glhooks.GetDriver()->CreateContext(data, NULL, GetInitParamsForDC(dc), false, false);
|
|
|
|
glhooks.m_HaveContextCreation = true;
|
|
|
|
SetLastError(err);
|
|
|
|
glhooks.m_CreatingContext = false;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static HGLRC WINAPI wglCreateContextAttribsARB_hooked(HDC dc, HGLRC hShareContext,
|
|
const int *attribList)
|
|
{
|
|
// don't recurse
|
|
if(glhooks.m_CreatingContext)
|
|
return glhooks.wglCreateContextAttribsARB_realfunc(dc, hShareContext, attribList);
|
|
|
|
glhooks.m_CreatingContext = true;
|
|
|
|
int defaultAttribList[] = {0};
|
|
|
|
const int *attribs = attribList ? attribList : defaultAttribList;
|
|
vector<int> attribVec;
|
|
|
|
// modify attribs to our liking
|
|
{
|
|
bool flagsFound = false;
|
|
const int *a = attribs;
|
|
while(*a)
|
|
{
|
|
int name = *a++;
|
|
int val = *a++;
|
|
|
|
if(name == WGL_CONTEXT_FLAGS_ARB)
|
|
{
|
|
if(RenderDoc::Inst().GetCaptureOptions().apiValidation)
|
|
val |= WGL_CONTEXT_DEBUG_BIT_ARB;
|
|
else
|
|
val &= ~WGL_CONTEXT_DEBUG_BIT_ARB;
|
|
|
|
// remove NO_ERROR bit
|
|
val &= ~GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR;
|
|
|
|
flagsFound = true;
|
|
}
|
|
|
|
attribVec.push_back(name);
|
|
attribVec.push_back(val);
|
|
}
|
|
|
|
if(!flagsFound && RenderDoc::Inst().GetCaptureOptions().apiValidation)
|
|
{
|
|
attribVec.push_back(WGL_CONTEXT_FLAGS_ARB);
|
|
attribVec.push_back(WGL_CONTEXT_DEBUG_BIT_ARB);
|
|
}
|
|
|
|
attribVec.push_back(0);
|
|
|
|
attribs = &attribVec[0];
|
|
}
|
|
|
|
RDCDEBUG("wglCreateContextAttribsARB:");
|
|
|
|
bool core = false;
|
|
|
|
int *a = (int *)attribs;
|
|
while(*a)
|
|
{
|
|
RDCDEBUG("%x: %d", a[0], a[1]);
|
|
|
|
if(a[0] == WGL_CONTEXT_PROFILE_MASK_ARB)
|
|
core = (a[1] & WGL_CONTEXT_CORE_PROFILE_BIT_ARB);
|
|
|
|
a += 2;
|
|
}
|
|
|
|
SetLastError(0);
|
|
|
|
HGLRC ret = glhooks.wglCreateContextAttribsARB_realfunc(dc, hShareContext, attribs);
|
|
|
|
DWORD err = GetLastError();
|
|
|
|
// don't continue if creation failed
|
|
if(ret == NULL)
|
|
{
|
|
glhooks.m_CreatingContext = false;
|
|
return ret;
|
|
}
|
|
|
|
GLWindowingData data;
|
|
data.DC = dc;
|
|
data.wnd = WindowFromDC(dc);
|
|
data.ctx = ret;
|
|
|
|
glhooks.GetDriver()->CreateContext(data, hShareContext, GetInitParamsForDC(dc), core, true);
|
|
|
|
glhooks.m_HaveContextCreation = true;
|
|
|
|
SetLastError(err);
|
|
|
|
glhooks.m_CreatingContext = false;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static BOOL WINAPI wglChoosePixelFormatARB_hooked(HDC hdc, const int *piAttribIList,
|
|
const FLOAT *pfAttribFList, UINT nMaxFormats,
|
|
int *piFormats, UINT *nNumFormats)
|
|
{
|
|
return glhooks.wglChoosePixelFormatARB_realfunc(hdc, piAttribIList, pfAttribFList, nMaxFormats,
|
|
piFormats, nNumFormats);
|
|
}
|
|
static BOOL WINAPI wglGetPixelFormatAttribfvARB_hooked(HDC hdc, int iPixelFormat, int iLayerPlane,
|
|
UINT nAttributes, const int *piAttributes,
|
|
FLOAT *pfValues)
|
|
{
|
|
return glhooks.wglGetPixelFormatAttribfvARB_realfunc(hdc, iPixelFormat, iLayerPlane,
|
|
nAttributes, piAttributes, pfValues);
|
|
}
|
|
static BOOL WINAPI wglGetPixelFormatAttribivARB_hooked(HDC hdc, int iPixelFormat, int iLayerPlane,
|
|
UINT nAttributes, const int *piAttributes,
|
|
int *piValues)
|
|
{
|
|
return glhooks.wglGetPixelFormatAttribivARB_realfunc(hdc, iPixelFormat, iLayerPlane,
|
|
nAttributes, piAttributes, piValues);
|
|
}
|
|
|
|
// wglShareLists_hooked ?
|
|
|
|
static BOOL WINAPI wglMakeCurrent_hooked(HDC dc, HGLRC rc)
|
|
{
|
|
BOOL ret = glhooks.wglMakeCurrent_hook()(dc, rc);
|
|
|
|
DWORD err = GetLastError();
|
|
|
|
{
|
|
SCOPED_LOCK(glLock);
|
|
|
|
if(rc && glhooks.m_HaveContextCreation &&
|
|
glhooks.m_Contexts.find(rc) == glhooks.m_Contexts.end())
|
|
{
|
|
glhooks.m_Contexts.insert(rc);
|
|
|
|
glhooks.PopulateHooks();
|
|
}
|
|
|
|
GLWindowingData data;
|
|
data.DC = dc;
|
|
data.wnd = WindowFromDC(dc);
|
|
data.ctx = rc;
|
|
|
|
if(glhooks.m_HaveContextCreation)
|
|
glhooks.GetDriver()->ActivateContext(data);
|
|
}
|
|
|
|
SetLastError(err);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Make sure that even if internally SwapBuffers calls wglSwapBuffers we don't process both of
|
|
// them separately
|
|
bool m_InSwap = false;
|
|
|
|
static void ProcessSwapBuffers(HDC dc)
|
|
{
|
|
HWND w = WindowFromDC(dc);
|
|
|
|
if(w != NULL && glhooks.m_HaveContextCreation && !glhooks.m_InSwap)
|
|
{
|
|
SCOPED_LOCK(glLock);
|
|
|
|
RECT r;
|
|
GetClientRect(w, &r);
|
|
|
|
glhooks.GetDriver()->WindowSize(w, r.right - r.left, r.bottom - r.top);
|
|
|
|
glhooks.GetDriver()->SwapBuffers(w);
|
|
|
|
SetLastError(0);
|
|
}
|
|
}
|
|
|
|
static BOOL WINAPI SwapBuffers_hooked(HDC dc)
|
|
{
|
|
SCOPED_LOCK(glLock);
|
|
|
|
ProcessSwapBuffers(dc);
|
|
|
|
glhooks.m_InSwap = true;
|
|
BOOL ret = glhooks.SwapBuffers_hook()(dc);
|
|
glhooks.m_InSwap = false;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static BOOL WINAPI wglSwapBuffers_hooked(HDC dc)
|
|
{
|
|
SCOPED_LOCK(glLock);
|
|
|
|
ProcessSwapBuffers(dc);
|
|
|
|
glhooks.m_InSwap = true;
|
|
BOOL ret = glhooks.wglSwapBuffers_hook()(dc);
|
|
glhooks.m_InSwap = false;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static BOOL WINAPI wglSwapLayerBuffers_hooked(HDC dc, UINT planes)
|
|
{
|
|
SCOPED_LOCK(glLock);
|
|
|
|
ProcessSwapBuffers(dc);
|
|
|
|
glhooks.m_InSwap = true;
|
|
BOOL ret = glhooks.wglSwapLayerBuffers_hook()(dc, planes);
|
|
glhooks.m_InSwap = false;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static BOOL WINAPI wglSwapMultipleBuffers_hooked(UINT numSwaps, CONST WGLSWAP *pSwaps)
|
|
{
|
|
for(UINT i = 0; pSwaps && i < numSwaps; i++)
|
|
ProcessSwapBuffers(pSwaps[i].hdc);
|
|
|
|
glhooks.m_InSwap = true;
|
|
BOOL ret = glhooks.wglSwapMultipleBuffers_hook()(numSwaps, pSwaps);
|
|
glhooks.m_InSwap = false;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static LONG WINAPI ChangeDisplaySettingsA_hooked(DEVMODEA *mode, DWORD flags)
|
|
{
|
|
if((flags & CDS_FULLSCREEN) == 0 || RenderDoc::Inst().GetCaptureOptions().allowFullscreen)
|
|
return glhooks.ChangeDisplaySettingsA_hook()(mode, flags);
|
|
|
|
return DISP_CHANGE_SUCCESSFUL;
|
|
}
|
|
|
|
static LONG WINAPI ChangeDisplaySettingsW_hooked(DEVMODEW *mode, DWORD flags)
|
|
{
|
|
if((flags & CDS_FULLSCREEN) == 0 || RenderDoc::Inst().GetCaptureOptions().allowFullscreen)
|
|
return glhooks.ChangeDisplaySettingsW_hook()(mode, flags);
|
|
|
|
return DISP_CHANGE_SUCCESSFUL;
|
|
}
|
|
|
|
static LONG WINAPI ChangeDisplaySettingsExA_hooked(LPCSTR devname, DEVMODEA *mode, HWND wnd,
|
|
DWORD flags, LPVOID param)
|
|
{
|
|
if((flags & CDS_FULLSCREEN) == 0 || RenderDoc::Inst().GetCaptureOptions().allowFullscreen)
|
|
return glhooks.ChangeDisplaySettingsExA_hook()(devname, mode, wnd, flags, param);
|
|
|
|
return DISP_CHANGE_SUCCESSFUL;
|
|
}
|
|
|
|
static LONG WINAPI ChangeDisplaySettingsExW_hooked(LPCWSTR devname, DEVMODEW *mode, HWND wnd,
|
|
DWORD flags, LPVOID param)
|
|
{
|
|
if((flags & CDS_FULLSCREEN) == 0 || RenderDoc::Inst().GetCaptureOptions().allowFullscreen)
|
|
return glhooks.ChangeDisplaySettingsExW_hook()(devname, mode, wnd, flags, param);
|
|
|
|
return DISP_CHANGE_SUCCESSFUL;
|
|
}
|
|
|
|
static PROC WINAPI wglGetProcAddress_hooked(const char *func)
|
|
{
|
|
PROC realFunc = glhooks.wglGetProcAddress_hook()(func);
|
|
|
|
#if 0
|
|
RDCDEBUG("Checking for extension - %s - real function is %p", func, realFunc);
|
|
#endif
|
|
|
|
// if the real RC doesn't support this function, don't bother hooking
|
|
if(realFunc == NULL)
|
|
return realFunc;
|
|
|
|
if(!strcmp(func, "wglCreateContextAttribsARB"))
|
|
{
|
|
glhooks.wglCreateContextAttribsARB_realfunc = (PFNWGLCREATECONTEXTATTRIBSARBPROC)realFunc;
|
|
return (PROC)&wglCreateContextAttribsARB_hooked;
|
|
}
|
|
if(!strcmp(func, "wglChoosePixelFormatARB"))
|
|
{
|
|
glhooks.wglChoosePixelFormatARB_realfunc = (PFNWGLCHOOSEPIXELFORMATARBPROC)realFunc;
|
|
return (PROC)&wglChoosePixelFormatARB_hooked;
|
|
}
|
|
if(!strcmp(func, "wglGetPixelFormatAttribfvARB"))
|
|
{
|
|
glhooks.wglGetPixelFormatAttribfvARB_realfunc = (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)realFunc;
|
|
return (PROC)&wglGetPixelFormatAttribfvARB_hooked;
|
|
}
|
|
if(!strcmp(func, "wglGetPixelFormatAttribivARB"))
|
|
{
|
|
glhooks.wglGetPixelFormatAttribivARB_realfunc = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)realFunc;
|
|
return (PROC)&wglGetPixelFormatAttribivARB_hooked;
|
|
}
|
|
|
|
HookCheckGLExtensions();
|
|
|
|
// assume wgl functions are safe to just pass straight through
|
|
if(!strncmp(func, "wgl", 3))
|
|
return realFunc;
|
|
|
|
CheckUnsupported();
|
|
|
|
// for any other function, if it's not a core or extension function we know about,
|
|
// just return NULL
|
|
return NULL;
|
|
}
|
|
|
|
WrappedOpenGL *m_GLDriver;
|
|
|
|
GLHookSet GL;
|
|
|
|
bool m_PopulatedHooks;
|
|
bool m_HasHooks;
|
|
bool m_EnabledHooks;
|
|
|
|
set<HGLRC> m_Contexts;
|
|
|
|
bool SetupHooks()
|
|
{
|
|
bool success = true;
|
|
|
|
success &=
|
|
wglCreateContext_hook.Initialize("wglCreateContext", DLL_NAME, wglCreateContext_hooked);
|
|
success &=
|
|
wglDeleteContext_hook.Initialize("wglDeleteContext", DLL_NAME, wglDeleteContext_hooked);
|
|
success &= wglCreateLayerContext_hook.Initialize("wglCreateLayerContext", DLL_NAME,
|
|
wglCreateLayerContext_hooked);
|
|
success &= wglMakeCurrent_hook.Initialize("wglMakeCurrent", DLL_NAME, wglMakeCurrent_hooked);
|
|
success &=
|
|
wglGetProcAddress_hook.Initialize("wglGetProcAddress", DLL_NAME, wglGetProcAddress_hooked);
|
|
success &= wglSwapBuffers_hook.Initialize("wglSwapBuffers", DLL_NAME, wglSwapBuffers_hooked);
|
|
success &= wglSwapLayerBuffers_hook.Initialize("wglSwapLayerBuffers", DLL_NAME,
|
|
wglSwapLayerBuffers_hooked);
|
|
success &= wglSwapMultipleBuffers_hook.Initialize("wglSwapMultipleBuffers", DLL_NAME,
|
|
wglSwapMultipleBuffers_hooked);
|
|
success &= SwapBuffers_hook.Initialize("SwapBuffers", "gdi32.dll", SwapBuffers_hooked);
|
|
success &= ChangeDisplaySettingsA_hook.Initialize("ChangeDisplaySettingsA", "user32.dll",
|
|
ChangeDisplaySettingsA_hooked);
|
|
success &= ChangeDisplaySettingsW_hook.Initialize("ChangeDisplaySettingsW", "user32.dll",
|
|
ChangeDisplaySettingsW_hooked);
|
|
success &= ChangeDisplaySettingsExA_hook.Initialize("ChangeDisplaySettingsExA", "user32.dll",
|
|
ChangeDisplaySettingsExA_hooked);
|
|
success &= ChangeDisplaySettingsExW_hook.Initialize("ChangeDisplaySettingsExW", "user32.dll",
|
|
ChangeDisplaySettingsExW_hooked);
|
|
|
|
DLLExportHooks();
|
|
|
|
return success;
|
|
}
|
|
|
|
bool PopulateHooks()
|
|
{
|
|
void *moduleHandle = Process::LoadModule(DLL_NAME);
|
|
|
|
if(wglGetProcAddress_hook() == NULL)
|
|
wglGetProcAddress_hook.SetFuncPtr(
|
|
Process::GetFunctionAddress(moduleHandle, "wglGetProcAddress"));
|
|
|
|
wglGetProcAddress_hooked("wglCreateContextAttribsARB");
|
|
|
|
#undef HookInit
|
|
#define HookInit(function) \
|
|
if(GL.function == NULL) \
|
|
GL.function = (CONCAT(function, _hooktype))Process::GetFunctionAddress(moduleHandle, \
|
|
STRINGIZE(function));
|
|
|
|
// cheeky
|
|
#undef HookExtension
|
|
#define HookExtension(funcPtrType, function) wglGetProcAddress_hooked(STRINGIZE(function))
|
|
#undef HookExtensionAlias
|
|
#define HookExtensionAlias(funcPtrType, function, alias)
|
|
|
|
DLLExportHooks();
|
|
HookCheckGLExtensions();
|
|
|
|
CheckExtensions(GL);
|
|
|
|
// see gl_emulated.cpp
|
|
glEmulate::EmulateUnsupportedFunctions(&GL);
|
|
|
|
glEmulate::EmulateRequiredExtensions(&GL);
|
|
|
|
return true;
|
|
}
|
|
|
|
DefineDLLExportHooks();
|
|
DefineGLExtensionHooks();
|
|
|
|
/*
|
|
in bash:
|
|
|
|
function HookWrapper()
|
|
{
|
|
N=$1;
|
|
echo "#undef HookWrapper$N";
|
|
echo -n "#define HookWrapper$N(ret, function";
|
|
for I in `seq 1 $N`; do echo -n ", t$I, p$I"; done;
|
|
echo ") \\";
|
|
|
|
echo -en "\ttypedef ret (WINAPI *CONCAT(function, _hooktype)) (";
|
|
for I in `seq 1 $N`; do echo -n "t$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done;
|
|
echo "); \\";
|
|
|
|
echo -en "\tCONCAT(function, _hooktype) CONCAT(unsupported_real_,function);";
|
|
|
|
|
|
echo -en "\tstatic ret WINAPI CONCAT(function, _hooked)(";
|
|
for I in `seq 1 $N`; do echo -n "t$I p$I"; if [ $I -ne $N ]; then echo -n ", "; fi;
|
|
done;
|
|
echo ") \\";
|
|
|
|
echo -e "\t{ \\";
|
|
echo -e "\tstatic bool hit = false; if(hit == false) { RDCERR(\"Function \" \\";
|
|
echo -e "\t\tSTRINGIZE(function)\" not supported - capture may be broken\");hit = true;}\\";
|
|
echo -en "\treturn glhooks.CONCAT(unsupported_real_,function)( ";
|
|
for I in `seq 1 $N`; do echo -n "p$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done;
|
|
echo -e "); \\";
|
|
echo -e "\t}";
|
|
}
|
|
|
|
for I in `seq 0 17`; do HookWrapper $I; echo; done
|
|
|
|
*/
|
|
|
|
#undef HookWrapper0
|
|
#define HookWrapper0(ret, function) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)() \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(); \
|
|
}
|
|
|
|
#undef HookWrapper1
|
|
#define HookWrapper1(ret, function, t1, p1) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1) \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(p1); \
|
|
}
|
|
|
|
#undef HookWrapper2
|
|
#define HookWrapper2(ret, function, t1, p1, t2, p2) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2) \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(p1, p2); \
|
|
}
|
|
|
|
#undef HookWrapper3
|
|
#define HookWrapper3(ret, function, t1, p1, t2, p2, t3, p3) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3) \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(p1, p2, p3); \
|
|
}
|
|
|
|
#undef HookWrapper4
|
|
#define HookWrapper4(ret, function, t1, p1, t2, p2, t3, p3, t4, p4) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4) \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(p1, p2, p3, p4); \
|
|
}
|
|
|
|
#undef HookWrapper5
|
|
#define HookWrapper5(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(p1, p2, p3, p4, p5); \
|
|
}
|
|
|
|
#undef HookWrapper6
|
|
#define HookWrapper6(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(p1, p2, p3, p4, p5, p6); \
|
|
}
|
|
|
|
#undef HookWrapper7
|
|
#define HookWrapper7(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(p1, p2, p3, p4, p5, p6, p7); \
|
|
}
|
|
|
|
#undef HookWrapper8
|
|
#define HookWrapper8(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8) \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(p1, p2, p3, p4, p5, p6, p7, p8); \
|
|
}
|
|
|
|
#undef HookWrapper9
|
|
#define HookWrapper9(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9) \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(p1, p2, p3, p4, p5, p6, p7, p8, p9); \
|
|
}
|
|
|
|
#undef HookWrapper10
|
|
#define HookWrapper10(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10) \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
|
|
}
|
|
|
|
#undef HookWrapper11
|
|
#define HookWrapper11(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11) \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, \
|
|
p11); \
|
|
}
|
|
|
|
#undef HookWrapper12
|
|
#define HookWrapper12(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12) \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, \
|
|
p11, p12); \
|
|
}
|
|
|
|
#undef HookWrapper13
|
|
#define HookWrapper13(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12, t13); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13) \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, \
|
|
p11, p12, p13); \
|
|
}
|
|
|
|
#undef HookWrapper14
|
|
#define HookWrapper14(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12, t13, t14); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
|
|
t14 p14) \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, \
|
|
p11, p12, p13, p14); \
|
|
}
|
|
|
|
#undef HookWrapper15
|
|
#define HookWrapper15(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12, t13, t14, t15); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
|
|
t14 p14, t15 p15) \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, \
|
|
p11, p12, p13, p14, p15); \
|
|
}
|
|
|
|
#undef HookWrapper16
|
|
#define HookWrapper16(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15, t16, \
|
|
p16) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12, t13, t14, t15, t16); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
|
|
t14 p14, t15 p15, t16 p16) \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, \
|
|
p11, p12, p13, p14, p15, p16); \
|
|
}
|
|
|
|
#undef HookWrapper17
|
|
#define HookWrapper17(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15, t16, \
|
|
p16, t17, p17) \
|
|
typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \
|
|
t12, t13, t14, t15, t16, t17); \
|
|
CONCAT(function, _hooktype) CONCAT(unsupported_real_, function); \
|
|
static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \
|
|
t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \
|
|
t14 p14, t15 p15, t16 p16, t17 p17) \
|
|
{ \
|
|
static bool hit = false; \
|
|
if(hit == false) \
|
|
{ \
|
|
RDCERR("Function " STRINGIZE(function) " not supported - capture may be broken"); \
|
|
hit = true; \
|
|
} \
|
|
return glhooks.CONCAT(unsupported_real_, function)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, \
|
|
p11, p12, p13, p14, p15, p16, p17); \
|
|
}
|
|
|
|
DefineUnsupportedDummies();
|
|
|
|
/*
|
|
in bash:
|
|
|
|
function HookWrapper()
|
|
{
|
|
N=$1;
|
|
echo "#undef HookWrapper$N";
|
|
echo -n "#define HookWrapper$N(ret, function";
|
|
for I in `seq 1 $N`; do echo -n ", t$I, p$I"; done;
|
|
echo ") \\";
|
|
|
|
echo -e "\tCONCAT(unsupported_real_,function) = NULL;";
|
|
}
|
|
|
|
for I in `seq 0 17`; do HookWrapper $I; echo; done
|
|
*/
|
|
void SetUnsupportedFunctionPointersToNULL()
|
|
{
|
|
#undef HookWrapper0
|
|
#define HookWrapper0(ret, function) CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
#undef HookWrapper1
|
|
#define HookWrapper1(ret, function, t1, p1) CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
#undef HookWrapper2
|
|
#define HookWrapper2(ret, function, t1, p1, t2, p2) CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
#undef HookWrapper3
|
|
#define HookWrapper3(ret, function, t1, p1, t2, p2, t3, p3) \
|
|
CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
#undef HookWrapper4
|
|
#define HookWrapper4(ret, function, t1, p1, t2, p2, t3, p3, t4, p4) \
|
|
CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
#undef HookWrapper5
|
|
#define HookWrapper5(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) \
|
|
CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
#undef HookWrapper6
|
|
#define HookWrapper6(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6) \
|
|
CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
#undef HookWrapper7
|
|
#define HookWrapper7(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7) \
|
|
CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
#undef HookWrapper8
|
|
#define HookWrapper8(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8) \
|
|
CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
#undef HookWrapper9
|
|
#define HookWrapper9(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9) \
|
|
CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
#undef HookWrapper10
|
|
#define HookWrapper10(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10) \
|
|
CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
#undef HookWrapper11
|
|
#define HookWrapper11(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11) \
|
|
CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
#undef HookWrapper12
|
|
#define HookWrapper12(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12) \
|
|
CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
#undef HookWrapper13
|
|
#define HookWrapper13(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13) \
|
|
CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
#undef HookWrapper14
|
|
#define HookWrapper14(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14) \
|
|
CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
#undef HookWrapper15
|
|
#define HookWrapper15(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15) \
|
|
CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
#undef HookWrapper16
|
|
#define HookWrapper16(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15, t16, \
|
|
p16) \
|
|
CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
#undef HookWrapper17
|
|
#define HookWrapper17(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \
|
|
p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15, t16, \
|
|
p16, t17, p17) \
|
|
CONCAT(unsupported_real_, function) = NULL;
|
|
|
|
DefineUnsupportedDummies();
|
|
}
|
|
};
|
|
|
|
OpenGLHook OpenGLHook::glhooks;
|
|
|
|
const GLHookSet &GetRealGLFunctions()
|
|
{
|
|
return OpenGLHook::glhooks.GetRealGLFunctions();
|
|
}
|
|
|
|
GLPlatform &GetGLPlatform()
|
|
{
|
|
return OpenGLHook::glhooks;
|
|
}
|
|
|
|
Threading::CriticalSection &GetGLLock()
|
|
{
|
|
return glLock;
|
|
}
|
|
|
|
// dirty immediate mode rendering functions for backwards compatible
|
|
// rendering of overlay text
|
|
typedef void(WINAPI *GLGETINTEGERVPROC)(GLenum, GLint *);
|
|
typedef void(WINAPI *GLPUSHMATRIXPROC)();
|
|
typedef void(WINAPI *GLLOADIDENTITYPROC)();
|
|
typedef void(WINAPI *GLMATRIXMODEPROC)(GLenum);
|
|
typedef void(WINAPI *GLORTHOPROC)(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble);
|
|
typedef void(WINAPI *GLPOPMATRIXPROC)();
|
|
typedef void(WINAPI *GLBEGINPROC)(GLenum);
|
|
typedef void(WINAPI *GLVERTEX2FPROC)(float, float);
|
|
typedef void(WINAPI *GLTEXCOORD2FPROC)(float, float);
|
|
typedef void(WINAPI *GLENDPROC)();
|
|
|
|
static GLGETINTEGERVPROC getInt = NULL;
|
|
static GLPUSHMATRIXPROC pushm = NULL;
|
|
static GLLOADIDENTITYPROC loadident = NULL;
|
|
static GLMATRIXMODEPROC matMode = NULL;
|
|
static GLORTHOPROC ortho = NULL;
|
|
static GLPOPMATRIXPROC popm = NULL;
|
|
static GLBEGINPROC begin = NULL;
|
|
static GLVERTEX2FPROC v2f = NULL;
|
|
static GLTEXCOORD2FPROC t2f = NULL;
|
|
static GLENDPROC end = NULL;
|
|
|
|
const GLenum MAT_MODE = (GLenum)0x0BA0;
|
|
const GLenum MAT_MDVW = (GLenum)0x1700;
|
|
const GLenum MAT_PROJ = (GLenum)0x1701;
|
|
|
|
static bool immediateInited = false;
|
|
|
|
bool OpenGLHook::DrawQuads(float width, float height, const std::vector<Vec4f> &vertices)
|
|
{
|
|
if(!immediateInited)
|
|
{
|
|
HMODULE mod = GetModuleHandleA("opengl32.dll");
|
|
|
|
if(mod == NULL)
|
|
return false;
|
|
|
|
getInt = (GLGETINTEGERVPROC)GetProcAddress(mod, "glGetIntegerv");
|
|
if(!getInt)
|
|
return false;
|
|
pushm = (GLPUSHMATRIXPROC)GetProcAddress(mod, "glPushMatrix");
|
|
if(!pushm)
|
|
return false;
|
|
loadident = (GLLOADIDENTITYPROC)GetProcAddress(mod, "glLoadIdentity");
|
|
if(!loadident)
|
|
return false;
|
|
matMode = (GLMATRIXMODEPROC)GetProcAddress(mod, "glMatrixMode");
|
|
if(!matMode)
|
|
return false;
|
|
ortho = (GLORTHOPROC)GetProcAddress(mod, "glOrtho");
|
|
if(!ortho)
|
|
return false;
|
|
popm = (GLPOPMATRIXPROC)GetProcAddress(mod, "glPopMatrix");
|
|
if(!popm)
|
|
return false;
|
|
begin = (GLBEGINPROC)GetProcAddress(mod, "glBegin");
|
|
if(!begin)
|
|
return false;
|
|
v2f = (GLVERTEX2FPROC)GetProcAddress(mod, "glVertex2f");
|
|
if(!v2f)
|
|
return false;
|
|
t2f = (GLTEXCOORD2FPROC)GetProcAddress(mod, "glTexCoord2f");
|
|
if(!t2f)
|
|
return false;
|
|
end = (GLENDPROC)GetProcAddress(mod, "glEnd");
|
|
if(!end)
|
|
return false;
|
|
|
|
immediateInited = true;
|
|
}
|
|
|
|
GLenum prevMatMode = eGL_NONE;
|
|
getInt(MAT_MODE, (GLint *)&prevMatMode);
|
|
|
|
matMode(MAT_PROJ);
|
|
pushm();
|
|
loadident();
|
|
ortho(0.0, width, height, 0.0, -1.0, 1.0);
|
|
|
|
matMode(MAT_MDVW);
|
|
pushm();
|
|
loadident();
|
|
|
|
matMode(prevMatMode);
|
|
|
|
begin(eGL_QUADS);
|
|
|
|
for(size_t i = 0; i < vertices.size(); i++)
|
|
{
|
|
t2f(vertices[i].z, vertices[i].w);
|
|
v2f(vertices[i].x, vertices[i].y);
|
|
}
|
|
|
|
end();
|
|
|
|
getInt(MAT_MODE, (GLint *)&prevMatMode);
|
|
|
|
matMode(MAT_PROJ);
|
|
popm();
|
|
matMode(MAT_MDVW);
|
|
popm();
|
|
|
|
matMode(prevMatMode);
|
|
|
|
return true;
|
|
}
|