function DriftTexturePrecisionTest(highprecision, verbose, filterMode) % DriftTexturePrecisionTest([highprecision=0][, verbose=0][, filterMode=1]) % % This test finds the minimum useful subtexel stepsize of the graphics hardwares % texture coordinate interpolators. The minimum stepsize is the finest % subpixel stepwidth that the gfx-hardware can resolve into an image in a % meaningful way, e.g., for slow subpixel scrolling, drifting gratings and % such. % % It draws an alternating black-white pattern, reads it back, then draws % the pattern shifted by some small horizontal amount, reads it back and % compares the two drawn images. If they are different then the hardware % could resolve the subpixel increment into two different, properly shifted % images via bilinear texture interpolation. If they are the same then the % increment was too small to resolve for this hardware. The smallest % stepsize is found in multiple iterations that reduce the stepsize until % no difference is found anymore. % % The minimum resolvable stepsize for an ATI Mobility Radeon X1600 (e.g., % MacBook Pro) is 1/64 th of a pixel, which corresponds to 6 bits subpixel % accuracy. % % If the optional flag 'highprecision' is set to 1 or 2, then floating % point textures are used, instead of integer textures with 8 bit % resolution. 1 selects 16bpc float textures, 2 selects 32bpc float % textures. A setting of 3 or 4 selects also 16bpc or 32bpc float textures, % but additionally a special PTB GLSL interpolation shader is used instead % of the hard-wired interpolator of your gfx chip. This is computationally % more demanding and therefore slower, but it should provide higher % precision and better resolution. % History: % 15.04.2007 Written (MK). if nargin < 1 || isempty(highprecision) highprecision = 0; end if nargin < 2|| isempty(verbose) verbose = 0; end if highprecision > 2 highprecision = highprecision - 2; sflags = 2; else sflags = 0; end if nargin < 3 filterMode = []; end AssertOpenGL; screenNumber=max(Screen('Screens')); texsize=256; % Half-Size of the grating image. skewden = inf; KbReleaseWait; try % Open a double buffered fullscreen window and draw a gray background % to front and back buffers: PsychImaging('PrepareConfiguration'); PsychImaging('AddTask', 'General', 'UseRetinaResolution'); [w, screenRect] = PsychImaging('OpenWindow',screenNumber, 128); Screen('Flip', w); % Create one single static alternating black-white image: grating=zeros(2*texsize, 2*texsize); if highprecision mfactor = 1; else mfactor = 255; end for x=1:2*texsize for y=1:2*texsize % Contrast is 255, so we can resolve stepsizes down to 1/255th. grating(y,x)=mod(x,2)*mfactor; end end % Store testpattern in texture: tex=Screen('MakeTexture', w, grating, [], sflags, highprecision); % Definition of the drawn rectangle on the screen: dstRect=[0 0 texsize texsize]; dstRect=CenterRect(dstRect, screenRect); % We only sample one single pixel in the center of the display: sampleRect = OffsetRect(CenterRect([0 0 1 texsize], dstRect), 0, 0); den = 1; skewcount = 0; % Test for stepsizes down to 1/512 th of a texel. while den <= 512 && ~KbCheck shiftperframe = 1/den; count = 0; for i=0:texsize % Shift the aperture by "shiftperframe" pixels per frame: xoffset = mod(i*shiftperframe,2*texsize); % Define shifted srcRect that cuts out the properly shifted rectangular % area from the texture: srcRect=[xoffset 0 xoffset + texsize texsize]; % Draw texture: Screen('DrawTexture', w, tex, srcRect, dstRect, [], filterMode); % Read back 1 sample pixel from drawn texture for comparison: readimgin = Screen('GetImage', w, sampleRect, 'backBuffer'); readimg = double(readimgin(10,1,1)); readimg2 = double(readimgin(:,1,1)); diffv = (abs(readimg - readimg2) > 0); if any(diffv) skewcount = skewcount + 1; end Screen('FillRect', w, [255 255 0], sampleRect) Screen('Flip', w); if (i > 0) % Any difference in pixels value? difference=abs(readimg - oldreadimg); if verbose fprintf('Sample was %f --> Delta for offset %f is %f\n', readimg, xoffset, difference); end % Count number of frames with non-differences: if difference == 0 count = count + 1; end else %KbWait; %while KbCheck; end; end % Update: oldreadimg = readimg; % Abort test if any key is pressed: if KbCheck break; end end % Output number of identical pixels in texsize samples sample set. % A count of 0 means that the chosen stepsize is still below the % resolution of the hardwares texture interpolators: fprintf('Stepsize 1 / %i th pixel. Nr. of identical frames: %i', den, count); if skewcount > 0 fprintf(' -- Warning: Interpolator skew detected! Your hardware is sampling inaccurate!\n'); skewden = min(skewden, den); else fprintf('\n'); end skewcount = 0; if count < 2 % Store this stepsize as our current best: bestden = den; end % Half the stepsize for next test run: den = den * 2; end if den > 512 % Output smallest stepsize that the texture coordinate interpolators of % the hardware can reliably resolve: fprintf('\n\nMinimum useable stepsize for interpolator is 1 / %i th of a pixel.\n', bestden); else fprintf('\n\nTest prematurely aborted, results therefore incomplete:\nFinest tested useable stepsize for interpolator is 1 / %i th of a pixel.\n', bestden); end if bestden > skewden || skewden == 1 fprintf('However, due to interpolator skew in your hardware, you may already encounter precision issues at a\nstepsize of 1 / %i th of a pixel.\n', skewden); fprintf('If you need absolute precision, e.g, for very strictly controlled low-level stimuli, you should not use a\n'); fprintf('stepsize finer than that. You may retry with "highprecision" settings greater than the currenly selected\n'); fprintf('setting, to see if your hardware behaves more accurately with such settings.\n\n'); end Screen('CloseAll'); catch %this "catch" section executes in case of an error in the "try" section %above. Importantly, it closes the onscreen window if its open. Screen('CloseAll'); psychrethrow(psychlasterror); end %try..catch..