Current version

v1.10.4 (stable)

Navigation

Main page
Archived news
Downloads
Documentation
   Capture
   Compiling
   Processing
   Crashes
Features
Filters
Plugin SDK
Knowledge base
Donate
Contact info
Forum
 
Other projects
   Altirra

Search

Calendar

« April 2014
S M T W T F S
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30      

Archives

01 Aug - 31 Aug 2013
01 May - 31 May 2013
01 Mar - 31 Mar 2013
01 Feb - 29 Feb 2013
01 Dec - 31 Dec 2012
01 Nov - 30 Nov 2012
01 Oct - 31 Oct 2012
01 Sep - 30 Sep 2012
01 Aug - 31 Aug 2012
01 June - 30 June 2012
01 May - 31 May 2012
01 Apr - 30 Apr 2012
01 Dec - 31 Dec 2011
01 Nov - 30 Nov 2011
01 Oct - 31 Oct 2011
01 Sep - 30 Sep 2011
01 Aug - 31 Aug 2011
01 Jul - 31 Jul 2011
01 June - 30 June 2011
01 May - 31 May 2011
01 Apr - 30 Apr 2011
01 Mar - 31 Mar 2011
01 Feb - 29 Feb 2011
01 Jan - 31 Jan 2011
01 Dec - 31 Dec 2010
01 Nov - 30 Nov 2010
01 Oct - 31 Oct 2010
01 Sep - 30 Sep 2010
01 Aug - 31 Aug 2010
01 Jul - 31 Jul 2010
01 June - 30 June 2010
01 May - 31 May 2010
01 Apr - 30 Apr 2010
01 Mar - 31 Mar 2010
01 Feb - 29 Feb 2010
01 Jan - 31 Jan 2010
01 Dec - 31 Dec 2009
01 Nov - 30 Nov 2009
01 Oct - 31 Oct 2009
01 Sep - 30 Sep 2009
01 Aug - 31 Aug 2009
01 Jul - 31 Jul 2009
01 June - 30 June 2009
01 May - 31 May 2009
01 Apr - 30 Apr 2009
01 Mar - 31 Mar 2009
01 Feb - 29 Feb 2009
01 Jan - 31 Jan 2009
01 Dec - 31 Dec 2008
01 Nov - 30 Nov 2008
01 Oct - 31 Oct 2008
01 Sep - 30 Sep 2008
01 Aug - 31 Aug 2008
01 Jul - 31 Jul 2008
01 June - 30 June 2008
01 May - 31 May 2008
01 Apr - 30 Apr 2008
01 Mar - 31 Mar 2008
01 Feb - 29 Feb 2008
01 Jan - 31 Jan 2008
01 Dec - 31 Dec 2007
01 Nov - 30 Nov 2007
01 Oct - 31 Oct 2007
01 Sep - 30 Sep 2007
01 Aug - 31 Aug 2007
01 Jul - 31 Jul 2007
01 June - 30 June 2007
01 May - 31 May 2007
01 Apr - 30 Apr 2007
01 Mar - 31 Mar 2007
01 Feb - 29 Feb 2007
01 Jan - 31 Jan 2007
01 Dec - 31 Dec 2006
01 Nov - 30 Nov 2006
01 Oct - 31 Oct 2006
01 Sep - 30 Sep 2006
01 Aug - 31 Aug 2006
01 Jul - 31 Jul 2006
01 June - 30 June 2006
01 May - 31 May 2006
01 Apr - 30 Apr 2006
01 Mar - 31 Mar 2006
01 Feb - 29 Feb 2006
01 Jan - 31 Jan 2006
01 Dec - 31 Dec 2005
01 Nov - 30 Nov 2005
01 Oct - 31 Oct 2005
01 Sep - 30 Sep 2005
01 Aug - 31 Aug 2005
01 Jul - 31 Jul 2005
01 June - 30 June 2005
01 May - 31 May 2005
01 Apr - 30 Apr 2005
01 Mar - 31 Mar 2005
01 Feb - 29 Feb 2005
01 Jan - 31 Jan 2005
01 Dec - 31 Dec 2004
01 Nov - 30 Nov 2004
01 Oct - 31 Oct 2004
01 Sep - 30 Sep 2004
01 Aug - 31 Aug 2004

Stuff

Powered by Pivot  
XML: RSS feed 
XML: Atom feed 

§ Things you find in the kitchen

I've been doing some work in the video capture routines in VirtualDub lately, and when I do that I tend to just grab the nearest video source as fodder. Usually it's the GameBridge hooked up to a PS2 running a random game, but today I grabbed the webcam, so it's time to take pictures of random stuff around the house.

Take, for instance, this knife sheath I found in the kitchen:

[NVIDIA-branded knife sheath]

I apologize for the poor quality image I never said this was a good webcam but the homemade cardboard sheath says "knife edge here" and there is an NVIDIA logo on it. "GeForce MX" is partly visible and as such I suspect this was the most useful part of the product.

(This is my revenge for the time I got made fun of for using my ATI RADEON X1800 XL, still in its original packaging, as a writing pad.)

(Read more....)

§ Just say no to cut-and-paste coding

Far more often than I would like, I see code like this:

if (p[x+1]->GetSomeObject()) {
    p[x+1]->GetSomeObject()->DoSomething();
    p[x+1]->GetSomeObject()->DoSomethingElse();
}

...with lots and lots of redundant expressions. I've always wondered why people code like this, because it's an awful practice. Is it concise? No, it's nauseatingly redundant. Is it fast? No, it has lots of redundant operations. My only plausible guess is that it is easier to type somehow because the person who wrote it was adept at cut-and-paste operations, and even in that case it seems sub-optimal, when you could write this instead:

Blah *base = p[x+1];
SomeObject *obj = base->GetSomeObject();
if (obj) {
    obj->DoSomething();
    obj->DoSomethingElse();
}

I see this anti-pattern most often in C++, but that's mainly because I look at C++ code most often; I've also seen it in C# and other languages too. It seems widespread enough that I can only conclude that either:

The first is a virtual certainty, but the second is something I can't discount, because I've seen some horrid practices taught in avenues of learning before. Academia is notorious for being littered with brilliant researchers who stink at programming, and so perhaps picking on it is a bit too easy; on the other hand, I still have nightmares about a popular C++ data structures textbook in which the author's code called exit() from a constructor to flag an error and had "friend void main();" in a class declaration.

Probably the most irritating issue with this practice, though, is that I've heard it defended with "the optimizer will fix it." Well, readability issues aside, this assumes there is an optimizer at all, which there isn't in a debug build. Without an optimizer, such explicitly redundant code can execute very slowly... to say nothing of being a pain to step through during debugging as well. This also puts unnecessary strain on the optimizer, making it re-deduce simple equivalences over and over when it should be spending its cycles doing more interesting optimizations like virtual method inlining and auto-vectorization.

The third problem is that it assumes the optimizer can remove the redundancy at all. In fact, it's fairly likely that it won't, because optimizers have incomplete information and are necessarily very pessimistic. In the above case, an optimizer has to assume that the return value from GetSomeObject() may change with each call unless it has concrete information indicating otherwise and given code visibility, aliasing, and polymorphism concerns, this determination frequently fails. If there is any valid way in which the return values from the calls would not be the same, no matter how unusual, weird, or useless the code would be, the optimizer cannot collapse the calls. If it does, that's called bad code generation, and nobody wants that.

Don't be gratuitously redundant. Hoist out common subexpressions to variables, and both humans and compilers will appreciate it.

(Read more....)

§ _ReturnAddress() is my favorite compiler intrinsic

I'm sick with a cold at the moment, so I'll blog twice today. It'll somewhat make up for my not having blogged the entire month.

Visual C++ has a compiler intrinsic called _ReturnAddress() that gives the return address of the calling function. It exists back to at least VC6, but wasn't documented until VC7. This has become my favorite intrinsic, because you can do lots of evil debugging hacks with it, and it's very fast. There's a known issue with this intrinsic that if the function is inlined the intrinsic returns the return address above the inline site, but I've found that's actually sometimes desirable behavior.

Got a memory leak and the caller didn't provide file/line information when allocating? Overload operator new, call _malloc_dbg() with the return address as the line number, and track down the call site from the leak report. I use this in shutdown of debug builds of VirtualDub, along with DbgHelp, to print names of guilty functions that leaked memory without requiring specially tagged operator new() calls. I also lookup the first four bytes of the memory block to check if it's a virtual method table pointer, which then also gives the type of object leaked.

If you are doing COM-style (AddRef/Release) reference counting, you've probably discovered what a pain it can be to track down a leak from a missing Release() call. It used to be that I'd do this by capturing and manually matching the call stacks of every AddRef() and Release() on a particular class, a very slow and laborious technique. VS2005 makes this a little easier because you can sometimes use tracepoints with $CALLSTACK, but it's still slow. My new favorite technique is to maintain a global map of all AddRef() and Release() callers by _ReturnAddress() and compile call counts by calling site. You can then quickly eliminate the smart pointer code quickly as long as the totals add up and then determine which call sites are involved and who screwed up manual reference counting.

My latest exploit involving _ReturnAddress() was to deal with a chatty DLL that was spewing to Win32 debug output, making it unusable for anything I was trying to debug. Solution: Patch the export for OutputDebugString() at runtime and redirect it to a function that used _ReturnAddress() to look up the calling DLL. Now I can filter debug traces by DLL.

_ReturnAddress() quickly becomes inadequate for more complex scenarios because it only gives you one level of stack walk. That's often sufficient, though, and since a real stack walk is so much more expensive (and on x86, unreliable) I find it a useful shortcut.

(Read more....)

§ DirectX vs. OpenGL

Igor writes:

Not only that Avery, just look at yourself using platform specific DirectX API instead of OpenGL -- how did they manage that?

Uh, well, it shouldn't be too surprising. I'm primarily a Win32/x86 programmer. To some people, it's a minor miracle anytime we write code that is in any way portable and doesn't declare at least one HRESULT variable per function.

In this specific case, it's more of an issue of practicality. I know both, I've used both, sometimes I prefer one over the other. I do like portable and multivendor APIs, but for me, deployment, ease of use, stability, and licensing are also factors.

Truth be told, I do like OpenGL better. It has a real spec, written in a precise manner, and the base API is better thought out than Direct3D, which has been hacked together over the years and still has garbage such as the infamous D3DERR_DEVICELOST. I learned a lot about 3D graphics by reading the OpenGL API and extension specs. It's portable, it makes easy things easy (like drawing one triangle), it's extensible, and it's faster since the application talks directly to the user-space IHV driver. Microsoft tried improving its API with Direct3D 10, but the documentation is still incomplete, it's still non-extensible, and it's even less portable than before since it's Vista-only.

Before anyone says anything else, though, theory and practice are a bit different. In practice, OpenGL drivers tend to have their own nice collections of bugs, and some are better optimized than others. Most games use Direct3D, so a lot of effort has been put into optimizing drivers and hardware for that API. Extensions also mean extension hell, and figuring out which extensions are widely available and work as advertised is just as frustrating as Direct3D caps hell. And then there's the shader issue whereas Direct3D has standardized assembly and HLSL shader languages, OpenGL has gone through numerous vendor-specific combiner-style, assembly-style, and high-level language shader extensions.

Now, as for how this pertains to what I do, well, VirtualDub isn't exactly a 3D centric application. It does have 3D display paths, and I have dabbled with hardware acceleration for video rendering as well, so here's my VirtualDub-centric take:

(Read more....)