Features new to VirtualDub 1.4 |
VirtualDub 1.4 contains a couple incremental changes to the filter SDK you might be interested in. If you want to use these extensions, but don't want to break compatibility with VirtualDub 1.2, you can do so by checking the vdfd_ver flag passed to your DLL's initialization function. This value is 4 for V1.2, 5 for V1.3d, and 6 for V1.4. By default, the sample init function given in the tutorial allows your filter to run under V1.2, so you will want to explicitly hardcode 6 in the return value if you need to use V1.4 functionality.
Exception handling |
The recommended course of action for VirtualDub 1.3 filters when failing a filter init or start is to return a non-zero value. Obviously, this is not very descriptive and leads to user confusion when a filter fails. Starting with VirtualDub 1.4, there are two new functions in the SDK in the FilterFunctions structure:
void (*ExceptOutOfMemory)();
void (*Except)(const char *format, ...);
The first is simple: you call it when you run out of memory. The second allows you to throw any descriptive error string, although keep it short please (<128 bytes is good). Both functions will abort your code by throwing a C++ exception back, so unless your code is simple enough to not require any exception handling, it is recommended that you either wrap code in try { } catch(...) { } handlers to clean up along the way, or implement your own exception handling and throw VirtualDub's exception at the end of the filter function.
You can only use these functions from within initProc, startProc, and runProc. Throwing exceptions anywhere else will cause crashes.
CPU detection |
VirtualDub 1.4 has vastly better CPU detection over previous versions. The third new function in FilterFunctions is getCPUFlags(). This function returns a bitfield which states all the CPU extensions you are allowed to use:
This flag tells you if the user has a really crappy CPU or not.
Windows supports FPU emulation for all systems, so you may safely use FPU instructions regardless. However, this flag tells you if you should do FPU-specific optimizations. Since there is only one CPU for which this is even faintly feasible, the Pentium, you can usually ignore this flag. (The Pentium is an oddball in that a floating-point multiply is more than three times faster than an integer one.)
This is the biggie. Pay attention to this flag, since MMX is a huge improvement over regular scalar code, mainly due to the extra registers.
This flag indicates that the CPU supports the subset of Intel's Streaming SIMD Extensions that only uses MMX registers. Among the instructions included are pshufw, pavgb, and pavgw. This flag is set for Pentium III and Athlon CPUs. AMD literature labels these instructions as "MMX extensions."
This flag indicates that the CPU supports the entire SSE instruction set, including the XMM registers. Athlon CPUs will have this flag clear, while it is set for Pentium III CPUs.
This flag indicates that the extension bit reserved for SSE2, slated to appear in the Pentium IV, is set.
If this appears, the CPU has support for AMD's 3DNow! extensions.
The CPU has support for the AMD 3DNow! extensions which appeared with the Athlon.
Reusing the stack pointer |
In the Win32 environment, it is possible to change ESP away from the stack, because interrupts do not occur on the user-mode stack. Although it is still recommended that you bump ESP down before accessing stack automatics, ESP can used to point to other data. VirtualDub 1.4 provides a way to do this while still allowing reentrancy; it is possible to code a routine that reuses ESP while being run concurrently on different threads. To do this, the entire routine should be written in assembly language.
When VirtualDub starts a thread, it initializes the application dword at fs:[14h] to a thread-specific data structure. The first 68 bytes of this structure are reserved for functions that wish to reuse ESP, with the top four bytes used for ESP itself. That means, to reuse ESP, you should code as follows:
mov eax,dword ptr fs:[14h] ;[move stack values into thread-specific space] mov dword ptr [eax+40h],esp mov esp,new_value ... mov eax,dword ptr fs:[14h] mov esp,dword ptr [eax+40h]
All values in the first 64 bytes pointed to by fs:[14h] should be considered forfeit as soon as you jump away from the current function in any way; this includes calling VirtualDub functions or returning from filter functions. You should not store non-constant values for your inner loop in global variables, as this will make your routine non-reentrant. If you need to use absolute addressing, copy the code block to a new memory area and relocate the addresses to new locations. Also, do not call any VirtualDub functions with ESP set away from the normal stack -- you may derail exception handling if you do so. Finally, never modify fs:[14h] under any circumstances.
Be aware that debugging a routine that modifies ESP may inhibit your ability to debug the routine. You should attempt to optimize the routine with a regular stack pointer before freeing up ESP for an 8th register.
VirtualDub external filter SDK 1.03 | ©1999-2000 Avery Lee (uleea05@umail.ucsb.edu) |