function ScreenTest(screenNumber)
% ScreenTest([screenNumber])
% 
% Usually you'll call this with no arguments, to test all screens.
%
% Win: 
%
% ScreenTest tests your computer's ability to show movies. It times the 
% interval between successive vertical blanking periods at various pixel 
% sizes and compares that to the nominal frame period.    ScreenTest also 
% reports facts about your computer's configuration as returned by 
% DescribeComputer. Bug reports of display-related problems should normally 
% be accompanied by a report from ScreenTest. This information is often useful 
% in diagnosis.
% 
% Mac: 
% 
% ScreenTest tests your computer's ability to show movies on each of 
% your screens. It times the processor and each video screen, documenting 
% the characteristics relevant to its use in vision experiments. We recommend
% running ScreenTest and FlickerTest anytime you want to check out a new
% configuration of computer, software, and display. Bug reports of
% display-related problems should normally be accompanied by a report from
% ScreenTest. This information is often crucial to diagnosis. Also see
% FlickerTest.
% 
% In practice, most display problems are associated with the screen's
% video driver. The driver software is usually supplied by the
% manufacturer of the video card. There are rules set by Apple that the
% drivers are supposed to conform to, but these rules are often broken.
% (Some of Apple's drivers break the rules too.) Vision research is very
% demanding of the driver, and problems slip past the quality control of
% the graphics card companies only to be caught by vision researchers.
% ScreenTest has evolved to help you detect and diagnose these problems.
% Once we've characterized the driver we can often customize the
% Psychtoolbox software to deal with that driver as a special case, to
% obtain standard performance at the user level. This allows your programs
% to run unchanged on all platforms.
% 
% The most common problem, by far, is getting the driver to wait for
% blanking when you load the clut (i.e. call cscSetEntries). For each
% screen, ScreenTest does a thorough test (pixelSizes 8, 16, 32 bits;
% several sequences of processor priority; loading one element or whole
% clut) and analyzes the results for you, identifying which parameters
% matter and which are irrelevant. Different parameters matter with
% different video drivers. Each new driver can be a surprise. When results
% are clear, we can then, when necessary, add special-case code to the
% Psychtoolbox to use SetClut in the appropriate way for each video card
% and driver to obtain the best performance. You can ignore all this
% behind-the-scenes activity, and just enjoy the fact that your programs
% run accurately, unchanged, on all platforms.
% 
% THE SCREENTEST REPORT
% 
% The first three lines of the report are printed by DescribeComputer to
% characterize the computing environment:
% 
% 	*** Denis Pelli's PowerBook G4/500, Mac OS 9.2.2 *************************
% 	G4, 500 MHz, memory bus 100 MHz, 80.026 Mflop/s
% 	Psychtoolbox 2.45, 1 August 2001, Matlab 5.2.1.1421
% 
% The next three lines are printed by DescribeScreen to characterize the
% driver and display:
% 
% 	*** Screen 0 *************************************************************
% 	PowerBook G4/500 ATY,RageM3p12A (.Display_Rage128 version 1.0f94)
% 	8 bit dacs. 1152x768 60 Hz.
% 
% "ATY,RageM3p12A" is the graphics card name. ".Display_Rage128" is the
% graphics driver name. The precision of the graphics card dacs, "8 bit
% dacs", in principle may be deduced from the data size in the gamma table
% returned by the driver in response to a cscGetGamma call, but, because
% there are a few rogue drivers, the errant cases are corrected in
% PrepareScreen. "1152x768 60 Hz" are the spatial resolution and frame rate.
% 
% The six-line table is printed by ScreenTest itself:
% 
% 	 -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
% 	pixel size                          8    16    32     bits
% 	pages                               1     1     1
% 	CopyWindow (ie CopyBits)          171   174   173     MB/s
% 	SetClut suppresses ints. for       -0.0  -0.0   0.0   frames
% 	LoadClut vs. GetClut? ( 8 bits)     ==    ==    == 
% 	LoadClut vs. GetClut? (10 bits)     no    no    no 
% 	 -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
% 
% ¥ This shows all the pixel sizes supported by this driver. For each
% pixel size it shows how many video pages are available. Swapping among
% multiple video pages would be a very nice thing to do, but, for no
% obvious reason, the manufacturers hardly ever offer multiple pages. 
% ¥ The CopyWindow row shows how fast you can copy between windows, in MB/s,
% from memory to your graphics card. This rate is typically twice as fast
% for built-in graphics as for any graphics card on a standard bus (e.g.
% PCI). 
% ¥ "SetClut suppresses interrupts for 0.0 frames". This is rarely
% an issue today, but historically some drivers have blocked interrupts
% for a long time while loading the clut. This caused interrupts to be
% missed and makes life difficult. We suggest avoiding cards that do that.
% ¥ "LoadClut vs. GetClut?" shows the results of trying to read back the
% contents of the CLUT, accessing the specified number of bits. Success is
% indicated by equality "==". Reading back the wrong value would be
% indicated by "!=", which should be a cause for concern. Some graphics
% drivers will reject the SetGamma with more than 8 bits, which would be
% indicated here as "no". Some drivers don't support the GetClut call at
% some pixel sizes, which would be indicated here as "na", for "not
% available".
% 
% The next section is printed by SetClutWaitTest:
% 
% 	--------------------------------------------------------------------------
% 	Supports cscGetClutBehavior 
% 	1 SetClutDriverWaitsForBlanking
% 	NOTE: Disabling automatic priority dipping while testing driver.
% 	--------------------------------------------------------------------------
% 
% These lines document the current configuration. "cscGetClutBehavior" and
% cscSetClutBehavior are fairly new control calls that allow one to query
% about or demand that the graphics driver wait for blanking when loading
% the clut. "SetClutDriverWaitsForBlanking" is a flag (1=yes; 0=no) that
% Screen maintains in the PsychTable for each screen, indicating whether,
% based on Psychtoolbox testing, one may count on the driver to wait for
% blanking when we call SetClut. Note that we are ignoring the issue of
% when the CLUT changes. Our concern here is whether the driver waits
% until the beginning of blanking before returning from the SetClut call.
% "priority dipping" refers to priority sequences like "7/0", as explained
% below.
% 
% The next section of the table is also printed by SetClutWaitTest:
% 
% 	--------------------------------------------------------------------------
% 	SetClut waits for blanking (i.e. ~60 Hz) if parameters have these values:
% 	           prioritySequence 
% 	   60 Hz:               0/0 
% 	   59 Hz:               7/0 
% 	SetClut doesn't wait for blanking if parameters have these values:
% 	           prioritySequence 
% 	  274 Hz:               7/7 
% 	The following parameters don't affect whether SetClut waits for blanking:
% 	                clutEntries         pixelSize 
% 	--------------------------------------------------------------------------
% 
% SetClutWaitTest times SetClut for all your screens at various
% pixelSizes, at various priorities, possibly with a brief stint, on each
% iteration, at another priority, and loading a single entry or the whole
% CLUT, to discover what factors, if any, affect whether SetClut waits for
% blanking. That's a lot of data, which ScreenTest boils down to the
% succinct summary above.
% 
% "60 Hz:" is the result, the measured iteration rate of the SetClut loop.
% 	If SetClut waits for blanking then this will equal the FrameRate, 
% 	within measurement error of a few Hz.
% "prioritySequence" "7/0" specifies two processor priorities:
% 	"7" (first) is the priority at which we call SetClut,
% 	"0" (second) is another priority that we use momentarily in the loop.
% "clutEntries" is how many of the clut's entries we are loading,
% 	either 1 or all.
% "pixelSize" potentially could be 1, 2, 4, 8, 16, or 32 but we only test 
% 	8, 16, and 32.
% 
% "prioritySequence" deals with two issues: priority per se, and priority
% "dipping".
% 
% PRIORITY. Your computer can run at various priority levels, from 0 to 7.
% Most of the time the computer runs at priority 0. At priority 0 all
% interrupts can occur. Most users of the Psychtoolbox elect to use its
% facilities for running critical code at higher priority to minimize
% interruption and thus achieve more reliable timing. However, the user
% will often want to synchronize the running program to the display's
% blanking. At low priority (up to 1), one can use the blanking interrupt,
% but it is suppressed at priorities of 2 and higher. In that situation
% one can often use a call to SetClut to wait for blanking. Unfortunately
% some drivers that successfully wait for blanking at low priority fail to
% do so at high priority. (Sigh!) That's why we test the SetClut behavior
% at various priorities.
% 
% PRIORITY DIPPING is a trick discovered by Bob Dougherty in 1999. The ATI Rage
% 128 driver waits for blanking if the priority is low, e.g. "0/0", but
% doesn't if the priority is high "7/7". Bob discovered that the driver
% also waits if the priority is high when we call SetClut, but we
% momentarily drop priority low before our next call to SetClut, e.g.
% "7/0". The fix, installed automatically by the Psychtoolbox, but
% disabled during this test, is to always momentarily dip the priority to
% 0 after every call to SetClut. We don't know why this works, but it does
% work, perfectly, with no undesired side effect that we are aware of. If
% you have a Rage 128 driver, then you'll see a ridiculously high loop
% rate (e.g. 274 Hz) in the ScreenTest results when priority is high "7/7"
% and the proper frame rate (e.g. 60 Hz) when the priority is low "0/0",
% or dips "7/0".
% 
% The final section of the table is printed by SetGammaWaitTest:
% 
% 	--------------------------------------------------------------------------
% 	SetGamma waits for blanking (i.e. ~60 Hz) if parameters have these values:
% 	           prioritySequence         pixelSize 
% 	   62 Hz:               0/0                16 
% 	   61 Hz:               7/0                16 
% 	   61 Hz:               0/0                32 
% 	   61 Hz:               7/0                32 
% 	SetGamma doesn't wait for blanking if parameters have these values:
% 	           prioritySequence         pixelSize 
% 	  308 Hz:               0/0                 8 
% 	  304 Hz:               7/0                 8 
% 	  309 Hz:               7/7                 8 
% 	  294 Hz:               7/7                16 
% 	  294 Hz:               7/7                32 
% 	The following parameters don't affect whether SetGamma waits for blanking:
% 	                clutEntries 
% 	**************************************************************************
% This is the same as the SetClut test, but applied to SetGamma. Many
% users never use SetGamma, but it is needed to achieve full precision
% with graphics cards that have more-than-8-bit DACs. The new
% LoadClut makes this easy to do. It uses SetClut and SetGamma. Its
% special-case handling of the various driver idiosynchrasies is based on
% the results of ScreenTest reports like this one.
%
% 
% NOTES
% 
% CUSTOMIZING THE PSYCHTOOLBOX: In the past, the special-case handling of video
% cards and drivers has been done in C in Screen.mex, but in Psychtoolbox
% 2.5 we have added calls to OpenWindow.m and CloseWindow.m that will make
% it possible for the customizations to be done in Matlab code, which is
% easier for us, and more accessible for you.
% 
% HISTORY: ScreenTest is a Matlab program, but what it does is similar to
% the TimeVideo standalone application provided by the VideoToolbox.
% Indeed, much of the underlying C code is shared. TimeVideo was under
% active development 1992 - 1995, with only minor updates since then,
% mostly to recompile it with enhanced source files. (TimeVideo often
% benefits from code changes made for ScreenTest.) ScreenTest was created
% in 1997, based partly on TimeVideo and partly on David Brainard's
% TimeBlankingTest.m, and has been actively improved since then. It is now
% substantially better than TimeVideo, making a more thorough assessment
% of the necessary conditions to get the driver to wait for blanking when
% we set the clut (i.e. call cscSetEntries or cscDirectSetEntries). Let us
% know if there's another measurement that ScreenTest should make.
% 
% BEGINNERS: ScreenTest will report some important facts about your
% computer, but if you're looking for a helpful example while writing your
% first movie program, look at MovieDemo and MovieDemo2.
% 
% SPEED RATING: To rate your computer, the most useful numbers are the
% number of floating point operations per second, Mflop/s, (measured for
% FFT2 of a 32x32 matrix), which characterizes how fast you can process
% images, and the unsynchronized CopyWindow rate, in MB/s, which
% characterizes how fast you can move pixels onto the screen. The two
% rates depend on different aspects of your computer's design. Mflop/s is
% determined primarily by the processor clock rate, except that the G4
% does nearly twice as many flops per clock cycle as all the preceding
% PowerPC chips (601, 603, and G3). MB/s is determined primarily by the
% clock rate of the bus that holds the video card. On most Macs, the
% internal memory bus (used by built-in video) is nearly twice as fast as
% the external bus (NuBus or PCI) that any additional video cards are
% plugged into.
% 
% BLANKING: Each video frame ends with blanking (black), caused by a
% pulse, sent from your computer's video card to your monitor. (Apple
% calls it "VBL", Vertical Blanking Level.) All frame counting and
% synchronization is done by reference to the beginning of blanking. The
% Screen PeekBlanking function tells you exactly when the last blanking
% interrupt occurred. (There may be some latency between the blanking and
% the servicing of the blanking interrupt, if another interrupt is being
% serviced at the time of the blanking pulse).
% 
% Rush.mex is used to minimize interruption of time-critical code. See
% Rush, Priority, RushTest, LoopTest.
% 
% COPYWINDOW (CopyBits) RATE: how fast CopyWindow can pump pixels, in
% MB/s. This depends mainly on the speed of the relevant bus: the memory
% bus for built-in video or the peripheral bus (PCI or NuBus) for a video
% card. The peripheral bus is half as fast as the memory bus on every
% Macintosh on which we've made the comparison, so you're
% better off using built-in video rather than buying a video card. 
% AGP and VRAM indicate that the offscreen window was stored in
% AGP or VRAM memory, using a new  experimental feature of Screen 
% OpenOffscreenWindow.
% 
% WINDOW ALIGNMENT: Highest copying speed is achieved when the processor
% can copy 32 bits at a time, and those bits are at 32-bit address
% boundaries. OpenOffscreenWindow automatically creates a pixmap that is
% appropriately aligned with the window/device that you supply for fast
% copying of the whole offscreen window. However, if you CopyWindow only a
% rect's worth, then for optimal speed the left and right boundaries of
% the rect should correspond to multiples of 32 bits. This only matters if
% you're optimizing speed.
% 
% TEARING: You may have seen "tearing" in the movie. The tear is a
% horizontal break, perhaps halfway down the screen, jiggling up and down
% as the movie played. This tear is normal and does not indicate anything
% wrong with your computer or the display software. Tearing can occur in
% any display that isn't double buffered, and hardly any of the drivers
% for Macintosh video cards support double buffering. Even so, it's easy
% to avoid tearing once you understand why it happens. See MovieTearDemo.
% 
% See also SetClutTest, WaitBlankingTest, PeekBlankingTest, FlickerTest,
% RushTest, PrepareScreen, RestoreScreen.

% 6/11/94	dhb	Wrote TimeBlankingTest.
% 3/16/97	dgp	Wrote ScreenTimeDemo, based on TimeBlankingTest.
% 3/20/97	dgp	Update frameRate measurement to use new PeekBlanking.
% 3/21/97	dgp	Measure max synchronized data rate.
% 3/27/97	dgp	Never use empty rect. Reduce image height by 10% each time.
% 3/27/97	dgp Correct centering.
% 3/27/97	dgp Add explanation of "unsynchronized" and "synchronized".
% 4/4/97	dgp Polish explanation of "unsynchronized" and "synchronized". Print it first.
%				Use bisection rule to home in on size of largest possible real-time movie.
%				Make real-time movie square, if possible.
%				To save time, use full-screen windows and merely adjust the size of the rect we copy.
% 4/11/97	dgp PatchTrap('GetMenuBar',10000);
% 4/11/97	dgp Variable name conflicted with built-in function. Rename version to driverVersion.
% 4/17/97	dgp Priority(0) before fprintf. This seems to prevent crashes, but I don't know
%				if it's actually necessary.
% 4/29/97	dgp All calls to Priority() have been removed. We only use Rush().
% 6/1/97	dgp Renamed ScreenTest.
% 6/3/97	dgp Cleaned up the print out. Fixed bug in bisection search.
% 6/4/97	dgp	Faster transfer of grating into offscreen window.
% 6/7/97	dgp	Cosmetic.
% 8/2/97	dgp	Cosmetic.
% 8/16/97	dgp	changed "text" to "theText" to avoid conflict with TEXT function.
% 1/12/98	dgp Changed "computerName" to "model". Added FlopPerSec. Tightened up the printout.
%				Added explanation, above, of Mflop/s and MB/s.
%				Enhanced printout of error conditions. Added "emulating" from new Screen.mex.
% 1/14/98	dgp Tightened up the priorityLevel printout. Report the WaitForVBLInterrupt pref.
% 2/1/98	dgp Leave FileSharing alone. I suspect that it doesn't affect RUSHed code.
% 2/16/98	dgp	Moved most of the tearing explanation to MovieTearingDemo.m.
% 3/2/98	dgp	Updated for char type of driverVersion returned by Screen 'VideoCard'.
% 3/2/98	dgp	Supply screenNumber (instead of 0) to MaxPriority.
% 3/13/98	dgp	Report new MaxPriorityForBlankingInterrupt.
% 3/14/98	dgp	Use FrameRate.m. 
% 3/14/98	dgp	Remove FileSharing tests, since I doubt FileSharing affects Rushed code.
% 3/23/98	dgp	Report QuickTime.
% 7/10/98	dgp	Report FileSharing since it affects MFlops.
% 7/14/98	dgp	Use new FrameRate and SetBlankingPrefs. 
% 7/14/98	dgp	Restrict movies on very large screens to reasonable size.
% 7/15/98	dgp Polished.
% 7/15/98	dgp Test all pixelSizes and print results in table, similar to the TimeVideo application
%				in the VideoToolbox.
% 7/21/98	dgp	Set GammaIdentity before testing SetClut vs. GetClut.
% 7/25/98	dgp	Updated to work with new prefs.
% 5/19/99	dgp	Report value of SetClutDriverWaitsForBlanking as "Yes" or "No".
% 9/18/99	dgp	Improved algorithm for calculating how long SetClut suppresses interrupts, 
% 				to fix bug reported by Bob Dougherty.
%				Warn when SetClut takes more than one frame.
% 9/20/99	dgp	Added missing brackets to line 295, as suggested by Bob Dougherty.
% 10/3/99	dgp	Removed call to AfterDark, now obsolete.
% 10/3/99	dgp	Updated to use new DriverTest.m instead of old FrameRate.m
% 10/5/99	dgp	Made printout more compact, suppressing SetClutDriverAwaitsBlanking 
%               unless it's inconsistent with SetClutDriverWaitsForBlanking.
% 10/28/99  dgp Cosmetic changes to accomodate the 6100.
% 11/1/99	dgp Report the new Preferences added to work around the bug in the Rage128 video driver.
% 2/15/00	dgp Cosmetic changes to reduce width, to pass through email without wrapping. 
% 				Email from keith schneider broke lines exceeding 74 characters.
% 6/21/00	dgp Test Screen Preference AskSetClutDriverToWaitForBlanking.
% 2/21/02	dgp Expand first paragraph of help to better explain the purpose.
% 4/24/02   awi Exit on PC with message.
% 4/29/02   awi Added DescribeComputer to the Windows branch. 
% 6/1/02    dgp Major change: Added SetClutWaitTest and deleted DriverTest.
% 6/8/02    dgp Call SetGammaWaitTest.
% 6/13/02   awi Added Windows section to time BLIT rates.
% 6/22/02   dgp Test for 10-bit-DAC support.
% 6/25/02   dgp Cleaned up for release.
% 7/26/02   dgp Fixed bug that could result in clut-test result of not available being falsely reported as "==".
% 8/1/02    dgp Made LoadClut test more rigorous, supplying a completely random full-precision clut to load and get.
% 8/12/02   dgp Measure CopyBits rate also for VRAM and AGP.
% 8/16/02   dgp Moved the Win: help ahead of the Mac: help, to make it easier to find.
% 2/19/02   awi Fixed bug in calculating the copy rate from measurements.

if IsPCWIN
    numIts=400; % number of times we loop under each condition.
    offscreenWindowSize = 400;
    oswRect = [0,0,offscreenWindowSize,offscreenWindowSize];
    wPixelSizes = Screen(0,'PixelSizes');
    wPriorities = [0:MaxPriority('WaitBlanking')];
    originalPriority=Priority;
	
    % preload stuff
    Screen;GetSecs;
	
    % time blits
    for p = 1:length(wPriorities)
        for i = 1:length(wPixelSizes)
            Priority(0);  % can't open or close a window if priority > 0 
            [w,wRect] = Screen(0,'OpenWindow',[],[],wPixelSizes(i));
            osw=Screen(w,'OpenOffscreenWindow',255,oswRect);
			Priority(wPriorities(p));
            tL(p,i) = GetSecs;
            for j=1:numIts
                Screen('CopyWindow',osw,w,oswRect,oswRect);   
			end
            tL(p,i) = GetSecs - tL(p,i);
            Priority(0); % can't open or close a window if priority > 0 
            Screen(osw,'Close');
            Screen(w,'Close');
		end
	end
    priority(originalPriority);
    
    % calculate summary
    for p = 1:length(wPriorities) % iterate over priorities
        for i = 1:length(wPixelSizes)
            blitRate(p,i) = offscreenWindowSize * offscreenWindowSize *  wPixelSizes(i) * numIts / 8  / tL(p,i) / 2^20 ;       
		end
	end 

    % display results
    fprintf('ScreenTest\n')
    DescribeComputer;
    DescribeScreen(-2);
    fprintf('Blit rate in MB/s\n');
    fprintf('%-16s','depth:');
    for i = 1:length(wPixelSizes)
        fprintf('%-10d',wPixelSizes(i)); 
	end
    fprintf('\n');
    for p = 1:length(wPriorities)
        fprintf('%-16s',['priority ' int2str(wPriorities(p))]);
        for i = 1:length(wPixelSizes)
            fprintf('%-10.4f',blitRate(p,i)); 
		end
        fprintf('\n');
	end 
    return;
end

if nargin==0
	clear screen; % start fresh
	if 0
		% If these 3 statements are on, then Matlab crashes some time after running ScreenTest on 
		% PowerBook Series G3/250, using August 10, 2000 version of Screen.mex.
		% As of 2/21/02, runs fine on original Titanium PowerBook G4/500, using latest Screen.mex.
		Screen(0,'openwindow',[],[0 0 20 20]); 
		Screen(0,'preference','waitblankingalwayscallssetclut',1);
		waitblankingalwayscallssetclut=Screen(0,'preference','waitblankingalwayscallssetclut')
	end

	fprintf('ScreenTest\n')
	DescribeComputer;
	for screenNumber=Screen('Screens') % Test every screen.
		ScreenTest(screenNumber);
	end
	DescribeScreen(-1); % end of table
	return
end

%%%%%%%%%%%%%%%%%%%%%%%%%%% Test and report on a screen. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Describe video card
DescribeScreen(screenNumber);
DescribeScreenPrefs(screenNumber);

% WARNING: ScreenTest: WaitBlankingAlwaysCallsSetClut is on, yet SetClutDriverWaitsForBlanking is off.
if Screen(screenNumber,'Preference','WaitBlankingAlwaysCallsSetClut') & ~Screen(screenNumber,'Preference','SetClutDriverWaitsForBlanking')
	fprintf('WARNING: ScreenTest: WaitBlankingAlwaysCallsSetClut is on, yet SetClutDriverWaitsForBlanking is off.\n');
end

DescribeScreen(-2);

[oldPixelSize,oldIsColor]=Screen(screenNumber,'PixelSize');
pixelSizes=Screen(screenNumber,'PixelSizes');
for ii=1:length(pixelSizes)
	Screen(screenNumber,'PixelSize',pixelSizes(ii),1);
	
	% pages, pixelSize
	[vTemp.pixelSize,vTemp.isColor,vTemp.pages]=Screen(screenNumber,'PixelSize');
	
	% GetClut
	oldClut=ClutDefault(screenNumber);
	[oldGamma,oldBits,gammaError]=Screen(screenNumber,'Gamma');
	if isempty(Screen(screenNumber,'GetClut'));
		vTemp.getClut=-1; % GetClut not available.
		vTemp.getClut8=-1; % GetClut not available.
	else
		% First try 8 bits.
		bits=8;
		setClut=floor(2^bits*rand([ScreenClutSize(screenNumber),3]));
		err=LoadClut(screenNumber,setClut,0,bits);
		if isempty(err)
			getClut=Screen(screenNumber,'GetClut',bits);
			vTemp.maxGetClutError8=max(max(abs(getClut-setClut)));
			vTemp.getClut8=vTemp.maxGetClutError8==0;
		else
			vTemp.getClut8=-2;
		end
	
		% Now try ScreenDacBits
		bits=ScreenDacBits(screenNumber);
		if bits==8
			bits=10;
		end
		setClut=floor(2^bits*rand([ScreenClutSize(screenNumber),3]));
		vTemp.getClutBits=bits;
		err=LoadClut(screenNumber,setClut,0,bits);
		if isempty(err)
			getClut=Screen(screenNumber,'GetClut',bits);
			vTemp.maxGetClutError=max(max(abs(getClut-setClut)));
			if vTemp.maxGetClutError>100
				% Try the opposite setting
				Screen(screenNumber,'Preference','UseHighGammaBits',~Screen(screenNumber,'Preference','UseHighGammaBits'));
				err=LoadClut(screenNumber,setClut,0,bits);
				Screen(screenNumber,'Preference','UseHighGammaBits',~Screen(screenNumber,'Preference','UseHighGammaBits'));
				getClut=Screen(screenNumber,'GetClut',bits);
				vTemp.maxGetClutError=max(max(abs(getClut-setClut)));
			end
			vTemp.getClut=vTemp.maxGetClutError==0;
		else
			vTemp.getClut=-2;
		end
	
		% Restore
		if ~gammaError.get
			Screen(screenNumber,'Gamma',oldGamma,oldBits);
		end
		Screen(screenNumber,'SetClut',oldClut);
	end

	vTemp.maxPriorityForBlankingInterrupt=Screen(screenNumber,'Preference','MaxPriorityForBlankingInterrupt');
	
	% suppresses interrupts
	s=0;j=0;k=0;f0=0;s0=0;f=0;s=0;reps=10;Screen('Screens'); % Make sure all rushed functions are in memory.
	priorityLevel=MaxPriority(screenNumber,'PeekBlanking','GetSecs');
	loop={
	'for k=1;'
	'Screen(screenNumber,''SetClut'',oldClut);'
	'[f0,s0]=Screen(screenNumber,''PeekBlanking'');'
	'for j=1:reps;'
	'Screen(screenNumber,''SetClut'',oldClut);'
	'end;'
	'[f,s]=Screen(screenNumber,''PeekBlanking'');'
	'end;'
	};
	oldSetClutPunches=Screen(screenNumber,'Preference','SetClutPunchesBlankingClock',0);
	Rush(loop,priorityLevel);
	Screen(screenNumber,'Preference','SetClutPunchesBlankingClock',oldSetClutPunches);
	f=f-f0; s=s-s0;
	vTemp.suppresses=(s*FrameRate(screenNumber)-f)/reps;
	vTemp.suppresses=vTemp.suppresses+0.004; % this tiny positive fudge helps to make the answer positive
	
	% CopyWindow
	vTemp.copyWindow=CopyBitsDataRate(screenNumber,'');
	vTemp.copyWindowAGP=CopyBitsDataRate(screenNumber,'AGP');
	vTemp.copyWindowVRAM=CopyBitsDataRate(screenNumber,'VRAM');
	
	v(ii)=vTemp;
end
fprintf('pixel size                     ');
fprintf('%6d',v(:).pixelSize);
fprintf('     bits\n');
fprintf('pages                          ');
fprintf('%6d',v(:).pages);
fprintf('\n');
for i=1:3
	switch i
	case 1,storage='';dataRate=[v(:).copyWindow];
	case 2,storage='AGP';dataRate=[v(:).copyWindowAGP];
	case 3,storage='VRAM';dataRate=[v(:).copyWindowVRAM];
	end
	if ~isempty(dataRate)
		fprintf('CopyWindow (ie CopyBits) %-4s  ',storage);
		switch floor(log10(min(dataRate/1e6)))
		case {4,3,2,1,0}, fprintf('%6.0f',dataRate/1e6); fprintf('   ');
		case -1, fprintf('  ');fprintf('%6.1f',dataRate/1e6); fprintf(' ');
		otherwise, fprintf('   ');fprintf('%6.2f',dataRate/1e6); fprintf('');
		end
		fprintf('  MB/s\n');
	end
end
fprintf('SetClut suppresses ints. for     ');
fprintf('%6.1f',v(:).suppresses);
fprintf('   frames\n');
fprintf('LoadClut vs. GetClut? (%2d bits)  ',8);
for i=1:length(pixelSizes);
	switch v(i).getClut8
	case 1, fprintf('   == '); % GetClut==SetClut
case 0, fprintf('%4d  ',v(i).maxGetClutError8); % GetClut~=SetClut
case -1,fprintf('   na '); % GetClut not available.
case -2,fprintf('   no '); % LoadClut error.
end
end
if any([v.getClut8]==0)
	fprintf('   #''s are max error.');
end
fprintf('\n');
if v(1).getClutBits>8
	fprintf('LoadClut vs. GetClut? (%2d bits)  ',v(1).getClutBits);
	for i=1:length(pixelSizes);
		switch v(i).getClut
		case 1, fprintf('   == '); % GetClut==SetClut
	case 0, fprintf('%4d  ',v(i).maxGetClutError); % GetClut~=SetClut
case -1,fprintf('   na '); % GetClut not available.
case -2,fprintf('   no '); % LoadClut error.
end
end
if any([v.getClut]==0)
	fprintf('   #''s are max error.');
end
fprintf('\n');
end

SetClutWaitTest(screenNumber);
SetGammaWaitTest(screenNumber);
% 	fprintf('WARNING: min duration exceeds a frame. You can''t load a new CLUT on every frame.\n');
return
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function rNew=AlignAndCenter(w,r)
screenNumber=Screen(w,'WindowScreenNumber');
screenRect=Screen(screenNumber,'Rect');
r=CenterRect(r,screenRect);
pixelSize=Screen(w,'PixelSize');
r([RectLeft RectRight])=round(r([RectLeft RectRight])*pixelSize/32)*32/pixelSize;
rNew=r;
return;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function dataRate=CopyBitsDataRate(screenNumber,storage)
% CopyWindow
% create one onscreen window, and a bunch of offscreen windows
pixelSize=Screen(screenNumber,'PixelSize');
r=Screen(screenNumber,'Rect');
b=RectWidth(r)*RectHeight(r)*pixelSize/8;
bMax=(bytes('Free')+bytes('TempFree')-1e6)/8;
bMax=min([1e6 bMax]);
bMax=max([bMax 0]);
if b>bMax
	r=AlignAndCenter(screenNumber,r*sqrt(bMax/b));
end
w=Screen(screenNumber,'OpenWindow',[],r);
theText=str2mat('Now computing an 8-frame movie,','to be shown asynchronously.');
Screen(w,'TextFont','Chicago');
Screen(w,'TextSize',18);
textWidth=Screen(w,'TextWidth',theText(1,:));
textHeight=size(theText,1)*Screen(w,'TextWidth','x');
textRect=CenterRect([0,0,textWidth,3*textHeight],Screen(w,'Rect'));
for i=1:size(theText,1)
	Screen(w,'DrawText',theText(i,:),textRect(RectLeft),textRect(RectTop)+i*textHeight,-1);
end
% 'PutImage' could expand our one-line grating to fill the image,
% but it's slow. Straight copying (replication) is the fastest operation, 
% so, instead, we ask 'CopyWindow' to expand to 1/4 height of image,
% and then replicate twice to fill the whole image.
rect=OffsetRect(r,-r(RectLeft),-r(RectTop));
lineRect=rect;
lineRect(RectBottom)=lineRect(RectTop)+1;
r1=rect;
r1(RectBottom)=rect(RectTop)+ceil(RectHeight(rect)/4);
r2=OffsetRect(r1,0,RectHeight(r1));
r3=rect;
r3(RectBottom)=rect(RectTop)+ceil(RectHeight(rect)/2);
r4=OffsetRect(r3,0,RectHeight(r3));
white=WhiteIndex(screenNumber);
black=BlackIndex(screenNumber);
for i=1:8
	oo=Screen(w,'OpenOffscreenWindow',[],[],[],storage,'noNewDevice');
	if isempty(oo)
		dataRate=[];
		Screen('CloseAll');
		return;
	end
	o(i)=oo;
	grating=1:RectWidth(rect);
	grating=i/8+3*grating/RectWidth(rect);
	grating=(1+sin(2*pi*grating))/2;	% range 0 to 1.
	grating=black+(white-black)*grating;
	Screen(o(i),'PutImage',grating,lineRect);
	Screen('CopyWindow',o(i),o(i),lineRect,r1);
	Screen('CopyWindow',o(i),o(i),r1,r2);
	Screen('CopyWindow',o(i),o(i),r3,r4);
end

% CopyWindow rate, asynchronous
% Make sure all Rushed functions are in memory.
s=0;j=0;k=0;rem(1,1);reps=30;GetSecs;Screen('Screens');
priorityLevel=MaxPriority('GetSecs');
loop={
'for k=1;'
	's=GetSecs;'
	'for j=1:reps;'
		'Screen(''CopyWindow'',o(1+rem(j,8)),w);'
	'end;'
	's=GetSecs-s;'
'end;'
};
Rush(loop,priorityLevel);
bytesCopied=reps*RectWidth(r)*RectHeight(r)*pixelSize/8;
dataRate=bytesCopied/s;
Screen(w,'Close');
for i=1:length(o)
	Screen(o(i),'Close');
end
return
