function DrawingSpeedTest(n,maxsize,primitivetype,mode,gpumeasure) % DrawingSpeedTest([n=800][,maxsize=80][,primitivetype=0][,mode=0][,gpumeasure=0]) % % Tests batch-drawing performance of some Screen functions. Batch drawing % is a way to submit multiple primitives, e.g., Filled Rects, at once. This % way the Matlab call overhead and some internal setup overhead is saved % and drawing should be significantly faster than when issuing single % drawing commands in a loop. % % This currently only tests filled rects and framed rects as well as filled % ovals. It also provides a way to test drawing by texture mapping. % Dots and Lines are nicely demonstrated by DotDemo and LinesDemo. % % The optional parameter 'n' allows to specifiy the number of primitives to % draw each frame, default is 800. The test loop will draw 1000 identical % frames and measure the time needed. % % 'maxsize' The maximum size of the primitive (width and height of covered % screen area) in pixels. Size of each primitive will be selected as a random % size between 1 pixel and 'maxsize' pixels. % % 'primitivetype' type of primitive: 0 = filled rects, 1 = framed rects, 2 % = filled ovals, 3 = framed ovals, 4 = filled arcs. % % 'mode' type of drawing: 0 = One by one submission (slowest), 1 = batch % submission, 2 = texture mapping for drawing, 3 = texture mapping with % batch submission of textures. % % 'gpumeasure' measurement type: 0 = Only on cpu. 1 = Measure exact % execution time of drawing commands on GPU's that support this feature. % Plot result at end of run. % % History: % 04/30/07 mk Wrote it. % 12/21/09 mk Add support for GPU measurement via EXT_timer_query on % supported hardware. if nargin < 1 || isempty(n) n = 800; end if nargin < 2 || isempty(maxsize) maxsize = 80; end if nargin < 3 || isempty(primitivetype) primitivetype = 0; else if ~ismember(primitivetype, [0, 1, 2, 3, 4]) error('Unsupported primitivetype specified. Must be 0 - 4.'); end end if nargin < 4 || isempty(mode) mode = 0; else if ~ismember(mode, [0, 1, 2, 3]) error('Unsupported mode specified. Must be 0 - 3.'); end end if nargin < 5 || isempty(gpumeasure) gpumeasure = 0; end % Check proper PTB installation: AssertOpenGL; % Open window with gray background on secondary display (if any): screenid = max(Screen('Screens')); [win, winrect] = Screen('OpenWindow', screenid, 128, [], [], [], [], 0); % Setup stim parameters: w=RectWidth(winrect); h=RectHeight(winrect); sizeX=maxsize; sizeY=maxsize; msize = min(w,h); % In mode 2 or 3, we draw a prototype stimulus into an offscreen window, % using the alpha-channel to mask out all non-stimulus shape pixels. We % will use this texture image of a prototype stim later on to draw the % stimulus shape, rescaling it and changing its color and alpha as % requested: if mode == 2 || mode == 3 % Need alpha-blending - Enable it: Screen('Blendfunction', win, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); % Open offscreen window 'template' of reasonable size msize x msize % pixels. Set it to a black transparent background [r g b a] = [0 0 0 0] template = Screen('OpenOffscreenWindow', win, [0 0 0 0], [0 0 msize msize]); % Draw prototype primitive which covers the full window and has a color % and alpha value of 255 ie. white and fully opaque: switch primitivetype case 0 Screen('FillRect', template, 255); case 1 Screen('FrameRect', template, 255, [0 0 msize msize], 50); case 2 Screen('FillOval', template, 255); case 3 Screen('FrameOval', template, 255); case 4 Screen('FillArc', template, 255, [], 45, 180); end end % Generate a matrix which specs n filled rectangles, with randomized % position, color and (dot-,line-)size parameter for j = 1:n posx = rand * w; posy = rand * h; colors(j, 1:3) = [ rand * 255, rand * 255, rand * 255]; %#ok<*AGROW> myrect(j, 1:4) = floor([ posx, posy, posx + rand * sizeX, posy + rand * sizeY]); sizes(j) = floor(rand * 10)+1; end % Need color and shape vectors transposed, i.e., 4 row by n columns % matrices: colors = transpose(colors); myrect = transpose(myrect); gpudur = zeros(1, 1000); % Initially sync us to retrace, take start time t1: t1 = Screen('Flip', win); % Timing loop, 1000 trials: for i=1:1000 if gpumeasure % Start GPU timer: gpumeasure will be true if this % is actually supported and will return valid results: gpumeasure = Screen('GetWindowInfo', win, 5); end % Batch draw: if mode < 2 switch primitivetype case 0 if mode == 1 % Batch drawing version of FillRect - submit all % primitives at once: Screen('FillRect', win, colors, myrect); end if mode == 0 for j=1:n % One part at a time submission: Screen('FillRect', win, colors(:,j)', myrect(:,j)'); end end case 1 if mode == 1 Screen('FrameRect', win, colors, myrect, sizes); end if mode == 0 for j=1:n Screen('FrameRect', win, colors(:,j)', myrect(:,j)', sizes(j)); end end case 2 if mode == 1 Screen('FillOval', win, colors, myrect); end if mode == 0 for j=1:n Screen('FillOval', win, colors(:,j)', myrect(:,j)'); end end case 3 if mode == 1 Screen('FrameOval', win, colors, myrect, sizes); end if mode == 0 for j=1:n Screen('FrameOval', win, colors(:,j)', myrect(:,j)', sizes(j)); end end case 4 % No batch drawing for FillArc: if mode == 0 || mode == 1 for j=1:n Screen('FillArc', win, colors(:,j)', myrect(:,j)', 33, 180); end end end else % mode > 2: Use DrawTexture to draw template primitive: if mode == 2 for j=1:n % DrawTexture in a loop: Screen('DrawTexture', win, template, [], myrect(:,j)', [], 0, [], colors(:,j)'); end else % Batch drawing version DrawTextures: Screen('DrawTextures', win, template, [], myrect, 0, 0, 0, colors); end end % Flip it. Don't clear buffers, don't sync to retrace. We want the raw % speed, nothing limited by monitor refresh: Screen('Flip', win, 0, 2, 2); % Result of GPU time measurement expected? if gpumeasure % Retrieve results from GPU load measurement: % Need to poll, as this is asynchronous and non-blocking, % so may return a zero time value at first invocation(s), % depending on how deep the rendering pipeline is: while 1 winfo = Screen('GetWindowInfo', win); if winfo.GPULastFrameRenderTime > 0 break; end end % Store it: gpudur(i) = winfo.GPULastFrameRenderTime; end % Next iteration. end % Make sure the GPU is idle: Screen('DrawingFinished', win, 2, 1); % Take end time, compute and print the stats: telapsed = GetSecs - t1; tavg = telapsed; tperrect = tavg / n; fprintf('Rendered 1000 frames, each with %i primitives of size %i x %i.\n', n, sizeX,sizeY); fprintf('Total cpu time %6.6f seconds. Time per primitive %6.6f msecs.\n', telapsed, tperrect); %Done. Screen('CloseAll'); if any(gpudur) gpudur = 1000 * gpudur; plot(gpudur); title('Drawtime in msecs per frame'); fprintf('Mean drawtime on GPU is %f msecs per frame, stddev = %f msecs, median %f msecs, time per primitive %6.6f msecs.\n', mean(gpudur), std(gpudur), median(gpudur), mean(gpudur)/n); end return;