Tuesday, May 19, 2009
Windows Installer
Wednesday, May 13, 2009
64-bit Win!
So the thing is, Sony Vegas as of 2009 still uses smoking hot DirectX Transform plugin technology. It's at least ten years old, DirectX Media saw its last release in the age of DirectX 6 (!), and that's really quite depressing. Why Sony, why? But despite this, ColorLab seems to be working and I'm impressed with Microsoft again. It could have been a nightmare but just... wasn't.
Now I just have to make a 64-bit installer and 1.0 RC2 is nearly at yer doorstep.
Friday, February 13, 2009
DLL headaches
In managing this per-process "engine", proper cleanup was the most problematic. When is it no longer needed? Any DLL "unloading" hooks would be too late. DLL_PROCESS_DETACH is also too late. So I was listening for DLL_THREAD_DETACH in my DllMain, and looking at _Module.GetLockCount() for a kind of "reference count". If this got down to zero, I assumed Vegas was no longer using my DLL and destroyed the engine. How naïve I was. It worked fine for a while, but after other revisions to my code GetModuleCount() didn't seem to reach zero any more.
Turns out, it's quite forbidden to do heavy cleanup involving threads and COM from within DllMain. In fact, don't do anything in DllMain unless it's explicitly allowed.
The solution for me was to explicitly reference count my back-end engine, and let the COM objects created from Vegas do an AddRef() in their constructor, and a Release() in their destructor. So when no more COM objects are active, the back-end is no longer needed and is destroyed. The shortcut I had taken turned out to be a slippery mountain road.
Moral of the story: be very very careful with DLL:s.
Saturday, February 7, 2009
White balance and highlight protection
Anyway, when you shift colors in this way, and some colors are clipped to pure white or nearly pure white in the original image (which has a bad color cast overall), those highlights of the image might look pretty ugly afterwards. See this clock for an example:
So I had to find my own way. After a little experimentation, and discussion with John O., I found a solution that seems to work at least most of the time. I added an option called "Protect highlights" to ColorLab, and made the strength of the effect configurable.
This looks a lot better. :) What the algorithm does is examine the R/G/B value of the original pixel, and depending on how close it is to the maximum (255 for each channel), it shifts the WB-corrected pixel towards a desaturated version of the original. Therefore the luma of the original is retained, while removing the original color cast.
I still have to test this technique on more images, but it looks promising.
Fast and easy float-to-int conversion with SSE
If your compiler has the “xmmintrin.h” header, you can probably use the SSE “intrinsics”, a set of functions replaced pretty much 1:1 with real instructions by the compiler. It will also do automatic register housekeeping for you, so it’s a vastly simplified way of getting access to SIMD instructions from C/C++.
For our conversion, the interesting instruction is _mm_cvtss_si32. It performs conversion of a single precision scalar with rounding, and should behave similarly to fistp. It’s not the fastest way to convert, but it’s a lot better than the standard (int). Going back to the article referenced above, _mm_cvtss_si32 does nearly as well as BitConvert23, yet passes the correctness test!
If you do want truncation, there is _mm_cvttss_si32 which does so, although without performance benefit. There are also actual SIMD versions of the instruction, converting two values at once. This may well be the overall winner, but for a drop-in replacement to (int), here’s a snippet that helped speed up my model data load times:
__forceinline int FastToInt( float f )
{
return _mm_cvtss_si32( _mm_load_ss( &f ) );
}
Saturday, May 3, 2008
Compressing normals (and other unit vectors)
A while ago I was thinking about compact GPU-friendly vertex data formats to use for normals and other unit vectors (tangents, bitangents etc).
Among the most interesting are DEC3N, which is 10 bit per component (-511..511), and the simple method of just quantizing to (-127..127) range and stuffing the vector in UBYTE4 or UBYTE4N. These all let you store a unit vector in a DWORD, but the precision is rather bad. The quantization can make the normals visibly different from the original floating point versions.
So it occurred to me that just using this “shell” of integers for unit vectors isn’t making good use of the representable values. You already know your unit vector is, well, unit length, so all you care about is the direction. And there are far more directions expressable as n-length vectors than there are ones expressable as unit vectors in a 3 byte tuple. Assuming adding a normalize() to your decoding step is cheap, we can exploit this!
(Click the image to magnify.)
I hacked up some code and made a compressor that takes a 3 float vector, uses 3D DDA to scan the “3-byte space” for useful candidates, finds the best of these, and spits out a 3 byte vector for you. The code is downright horrible, and I think I lifted the DDA code from the Interweb, but the idea should be clear enough to run with. Also, the compressor seems to work well for any game data I’ve thrown at it, and gives very low error compared to the original normal.
I intend to make a follow-up post with some error numbers, and improved code later. If anyone can find ways to improve it, please comment!
