function ClutRoundingTest
% Determine what is the best setting for Screen Preference
% SetClutDuplicates8Bits.
% 
% Measure effect of varying the lower 8 bits of the 16 bit clut entries
% (cspec) supplied when we call SetClut (cscSetEntries or
% cscDirectSetEntries). I had long assumed that the lower 8 bits were
% ignored, but it turns out that at least some ATI drivers use them.
% Various rounding formulas are used to convert the 16 bits to an 8 bit
% index into the gamma table. The ClutRoundingTest results indicate what
% one should put in the lower 8 bits to get an index equal to what one
% specifies in the upper 8 bits. Choose the rule that produces the column
% with least error.
% entry  = entry number, 0..255. 
% gamma  = value in gamma table (identical for r,g, and b)
% "0"    = error in GetClut when SetClut set lower 8 bits to zero.
% "dupe" = error in GetClut when SetClut set lower 8 bits to match upper 8.
% "255"  = error in GetClut when SetClut set lower 8 bits to 255 (max).
% 
% After testing several cards and drivers, we've come to the conclusion
% that in the end there are only two reasonable choices: 0 and dupe. These
% correspond to the two possible settings (0 and 1) of the Screen
% Preference SetClutDuplicates8Bits. The 0 setting is best for
% most graphics drivers. PrepareScreen runs a quick test and tries
% to make the best setting for each driver. If you find it's making the 
% wrong setting for your driver, then you may need to add a conditional to
% PrepareScreen.m to configure things properly for your driver. Please
% drop a line to the forum so we all know, and we can update PrepareScreen
% to incorporate everyone's enhancements.

% 8/3/02 dgp Wrote it.
% 8/5/02 dgp Cope with clutSize<256.

global screenGlobal
fprintf('ClutRoundingTest\n');
describecomputer;
for s=screen('screens');
	describescreen(s);
	describescreenprefs(s);
	oldDupe=Screen(s,'Preference','SetClutDuplicates8Bits',0);
	oldFix=screenGlobal(s+1).fixATIRadeon7000;
	screenGlobal(s+1).fixATIRadeon7000=0;
	bits=ScreenDacBits(s);
	clutSize=ScreenClutSize(s);
	gamma=bitshift([(0:255)' (0:255)' (0:255)']*257,bits-16);
	if isATIRadeon7000(s)
		inc=find(mod(gamma,341)~=0);
		g=gamma;
		g(inc)=g(inc)+1;
		SCREEN(s,'Gamma',g,bits);
	else
		SCREEN(s,'Gamma',gamma,bits);
	end
	clut=[(0:clutSize-1)' (0:clutSize-1)' (0:clutSize-1)'];
	clut16=bitshift(clut,8)+[zeros(clutSize,1) clut(:,2) ones(clutSize,1)*255];
	SCREEN(s,'SetClut',clut16,0,16);
	getClut=SCREEN(s,'GetClut',bits);
	c=getClut-[gamma(1+clut(:,1),1) gamma(1+clut(:,2),2) gamma(1+clut(:,3),3)];
	fprintf('entry gamma 0  dupe  255\n');
	for i=1:ScreenClutSize(s)
		fprintf('%3d %4d %4d %4d %4d\n',i-1,gamma(i,1),c(i,:));
	end
	Screen(s,'Preference','SetClutDuplicates8Bits',oldDupe);
	screenGlobal(s+1).fixATIRadeon7000=oldFix;
end
describescreen(-1);
