C++ How to replace a function but still use the original function in it?
I want to modify the glB开发者_C百科indTexture() function to keep track of the previously binded texture ID's. At the moment i just created new function for it, but then i realised that if i use other codes that use glBindTexture: then my whole system might go down to toilet.
So how do i do it?
Edit: Now when i thought it, checking if i should bind texture or not is quite useless since opengl probably does this already. But i still need to keep track on the previously used texture.
As Andreas is saying in the comment, you should check this is necessary. Still, if you want to do such a thing, and you use gnu linker (you don't specify the operating system) you could use the linker option:
--wrap glBindTexture
(if given directly to gcc you should write):
-Wl,--wrap,glBindTexture
As this is done at linker stage, you can use your new function with an already existing library (edit: by 'library' I mean some existing code which you can recompile but which you wouldn't want to modify).
The code for the 'replacement' function will look like:
void * __wrap_glBindTexture (GLenum target, GLuint texture) {
printf ("glBindTexture wrapper\n");
return __real_glBindTexture (target,texture);
}
You actually can do this. Take a look at LD_PRELOAD. Create a shared library that defines glBindTexture
. To call the original implementation from within the wrapper, dlopen
the real OpenGL library and use dlsym
to call the right function from there.
Now have all client code LD_PRELOAD your shared lib so that their OpenGL calls go to your wrapper.
This is the most common method of intercepting and modifying calls to shared libraries.
You can intercept and replace all calls to glBindTexture
. To do this you need to create your own OpenGL dll which intercepts all OpenGL function calls, does the bookkeeping you want and then forward the function calls to the real OpenGL dll. This is a lot of work so I would defintely think twice before going down this route...
Programs like GLIntercept work like this.
One possibility is to use a macro to replace existing calls to glBindTexture:
#define glBindTexture(target, texture) myGlBindTexture(target, texture)
Then in you code, where you want to ensure against using the macro, you surround the name with parentheses:
(glBindTexture)(someTarget, someTexture);
A function-like macro is only replace where the name is followed immediately by an open-parenthesis, so this prevents macro expansion.
Since this is a macro, it will only affect source code compiled with the macro visible, not an existing DLL, static library, etc.
I haven't ever worked with OpenGL, so not knowing anything about that function, here's my best guess. You would want to replace the glBindTexture function call with your new function's call anywhere it occurs in your code. If you use library functions that will call glBindTexture internally, then you should probably figure out a way to reverse what glBindTexture does. Then, anytime you call something that binds a texture, you can immediately call your reversal function to undo its changes.
The driver WON'T do it, it's in the spec. YOU have to ensure that you don't bind the same texture twice, so it's a good idea.
However, it's even a better idea to separate the concerns : let the low-level openGL deal with its low-level stuff, and your (thin, thick, as you want) abstraction layer do the higher-level stuff.
So, create a oglWrapper::BindTexture function that does the if(), but you should not play around with LD, even if this is technically possible.
[EDIT] In fact, it's not in the ogl spec, but still.
In general, the approaches have been catalogued under the heading of "seams", as popularized in M. Feather's 2004 book Working Effectively with Legacy Code. The book focuses on finding seams in a monolith application to isolate parts of it and put them under automated testing.
Feathers' seams can be found in the following places
- compiler
__attribute__ ((ifunc
in GCC, https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Function-Attributes.html
- preprocessor
- change what gets used with a
#define
- change what gets used with a
- linker
-Wl,--wrap,func_xyz
- linking order, first found symbol gets used, program can delegate using
dlsym(RTLD_NEXT, ...)
- the binary format has a Procedure Linkage Table which can be modified by the program itself when it runs
- in Java, much can be achieved in the JVM, see for example Mockito
- language features
- function pointers, this can actually be done so as to add no syntactic overhead at point of call!
- object inheritance: inherit, override, call super()
sources:
- https://www.informit.com/articles/article.aspx?p=359417&seqNum=3
- https://www.cute-test.com/guides/mocking-with-cute/
精彩评论