First: MSVC by default will align on natural alignment up to 32 bits, and thus will pad float-char-float with 3 bytes between the char and the float. This can be changed with compiler options and/or #pragmas. GCC has something similar with its type attribute syntax. Just running any type through the compiler will show you this.
Program:
#include <stdio.h>
struct foo {
float a;
char b;
float c;
};
int
main()
{
foo * f = 0;
printf( "%lx, %lx, %lx, %x
",
&f->a, &f->b, &f->c, sizeof( foo ) );
return 0;
}
Output (both using GCC 3.0.3 for i686 and MSVC 6.0 sp5):
0, 4, 8, c
Whoever said it didn’t and he’d just checked, obviously hadn’t, or checked something totally different (it was kind of vague, that comment).
Second: the native alignment size on any modern x86 is 32 bits, and smaller alignment may cost you performance. malloc(), as implemented in the MSVC runtime library, will do its darndest to return to you 32-bit aligned data. If you “randomly” access data (rather than streaming through it), it makes sense to pad out to powers of 2, and make sure your array starts on the same alignment, to be cache optimal about your accesses.
Third: 16 bits accesses are typically slower than 32 bit on a modern x86, because, if nothing else, each instruction using 16 bit registers needs a size prefix byte. Also, on not-so-modern x86 processors, you get a partial register stall if you mix 32 and 16 bit mode code without properly indicating that you don’t care about the upper bits by clearing the register with xor reg,reg.
Fourth: It is not possible to get optimal SSE throughput using non-padded 3-element vertices. The shuffle instruction will tie up the SSE execution unit for three (3!) cycles, and is thus more expensive than add or multiply. (Btw: P-III can only decode a single SSE instruction per clock, and Athlon XPs aren’t any faster at SSE than at regular FP
)
There may be cases where you can code your loop to “just work ™” with 3-interleaved vertex arrays, but that’s not the norm. If you can save memory and still be efficient, by all means, do so, but there’s many cases where padding actually does matter; all depending on your data access pattern.
Fifth: writing 3-aligned float triplets to AGP memory is a recipe for disaster, as the Pentium III has only 6 line fetch buffers (doubling as write combiners) and will evict a partially filled one at first hint of running low; thus, you REALLY want to be writing full, aligned 32-BYTE quantities at a time when going to AGP memory. No can do if your input or data format is only 12 byte aligned. Well, unless you write 96 bytes at a time, but at that point, you’re all out of LFBs to get data in from L2 or RAM in the first place…
Now, let’s return to our regularly scheduled hand-wringing over the total absence of released OpenGL drivers supporting ARB_fragment_program in hardware.