pea posted on Sep 4 2005 at  11:35 PM said:
			
		
	
	
		
		
			Here is my final solution.  I used una-i's solution of masking out the bits higher.  yet to test it:
	
	
	
		Code:
	
	
		unsigned short addColorChannel( const unsigned short dest, const unsigned short source, unsigned long shift){
   unsigned  dest_a = (dest>>shift) & 0x1F;  	// Destination colour channel in lower 5 bits
   unsigned  source_a = (source>>shift) & 0x1F;	// Source colour channel in lower 5 bits
                                                   
   dest_a  = source_a = dest_a + source_a;    // Sum of colours including overflow
   source_a &= 0x20;              	// Mask out overflow bit
   source_a -= (source_a>>5);          	// Create channel saturation mask from overflow bit
   dest_a |= source_a;              // Mask overflow
   
   return (dest & ~(0x1F<<shift)) | (dest_a & 0x1F)<<shift;	// Mask out channel and add back to dest
}
	 
 
Where:
dest is colour at destination
source is colour at source
shift is dependant on channel to mix (11=R, 6=G, 1=B )
What it should do:
Blend a single channel of the source colour with the whole destination colour
Doubts:
Need to benchmark it because I have my doubts that:
5 shifts, an addition, a subtraction and 7 binary operations
is faster than:
1 comparison/branch, 3 shifts, an addition and 2 binary operations
But then, what do I know 
		 
		
	 
I may sound a bit dickish, but this board is for discussing code aswell, so I wonder if my thoughts are correct AND I am still of the opinion that my code is the fastest 
My proposal has:
 2 shifts ( needed for aligning the  R G B values, could be leaved out for B value!)
 2 bitwise-operations ( needed to mask out all unneeded bits.
 1 add ( obviusoly needed for ADDitive-blending 

 1 compare ( which is the same computation as arithmetik ( SUB)
 and 1 simple move which is just executed when saturation should be done!
BTW, the "mov r4, #$1f" isn't needed, cause immeadite is as fast as register addressing, so just replace all "r4" to "#$1f", like: "and r0, r0, #$1f".
So we have 6 or 7 instructions compared to the 12 ( without branch) and the 7 ( with branch).
One of the key ideas is, that the saturated value and the AND-mask are always identical! The only thing I dont know by heart is, if the CPU issues a real NOP instruction when the condition for the "movGT" instruction isn't met and if then a pipeline flush occures as well. I see no need for that, but if it is implemented that way in the ARM 9 core, then my proposal hjas to be overthougth 
 
You can further use a specilized route for every channel, then you can get rid of the shifting, dont forget, you have to shift back your result, so you can save always a shift more for R and G channles.
looks like this:
	
	
	
		Code:
	
	
		MASK_R	equ $1f << 11
MASK_G	equ $1f <<  6
MASK_B	equ $1f
; for each channel do like the following
and r0, r2, #MASK_R; mask off
and r1, r3, #MASK_R;
add r0, r0, r1                  ; mix colors
cmp r0, #MASK_R        ; check for saturation
mov r0, #MASK_R        ; saturated value ( if needed)
	 
 
Further optimization is ofcourse possible when you caluclate two (16 bit) pixels in one (32-bit) word, then you have to use the carry bit for the overflow of the highest Red bit. But this approache is not so generic but ( obviuosly) delivers double the speed 
I would recommend to compile your C code to assembnler src ( -S option in GCC if I am not mistaken) and count the instructions. Because it is not guaranteed that the C compiler translates every C instruction with one ARM 9 instruction 
If your problem is to use the asm code, I can try to make a C macro for this ( asm statement). I never done it before, so I can't add it now.
Any corrections are highly welcomed, cause I have no time to test it and therefore can't say it is 100% correct. Sorry for this 
salut,
 creature