/usr/share/psychtoolbox-3/PsychTests/AlphaMultiplicationAccuracyTest.m is in psychtoolbox-3-common 3.0.11.20131230.dfsg1-1build1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | function [maximumError, roundTypeStr, independentFlag]=AlphaMultiplicationAccuracyTest(screenNumber)
% [maximumError, roundTypeStr, independentFlag]=AlphaMultiplicationAccuracyTest([screenNumber])
%
% Test the accuracy of alpha blending multiplication. OpenGL guarantees
% perfect accuracy of alpha multiplication for values 0 and 1 only.
% TestAlphaMultiplicationAccuracy measures accuracy of intermediate values.
%
% Return argument "maximumError" is the maximum unsigned difference between
% OpenGL alpha multiplication and simulated alpha blending in MATLAB using
% double-precisions floating point multiplication.
%
% Values of maximumError fall into three categories:
%
% 0 <= maximumError < 0.5 : OpenGL rounds to nearest integer. No
% accuracy loss for a single multiplication.
%
% 0.5 <= maximumError < 1 : OpenGL truncates or rounds up. For a single
% multiplication, Accuracy is off 0.5 parts
% in 255 more than would multiplying luminances
% using floating-point values and rounding.
%
% maximumError >= 1 : Something is wrong.
%
%
% TestAlphaMultiplicationAccuracy tries to determine whether OpenGL alpha
% multiplication rounds to the nearest integer, rounds down or rounds up
% and returns in "roundTypeStr" a string indicating which, either, "round"
% "floor", or "ceil". If TestAlphaMultiplicationAccuracy can not determine
% the rounding method, then it returns "unknown".
%
% TestAlphaMultiplicationAccuracy also tests that multiplication errors are
% independent of the choice of blending factor string and the blending
% surface, setting return argument "independentFlag" accordingly.
%
% Because in OpenGL pixel color components are ultimately encoded as 8-bit
% integers in video RAM, the results of OpenGL alpha multiplicaion will be
% less accurate than those predicted by floating-point calculations. If
% OpenGL rounds to the nearest integer then the alpha multiply error will
% be less than 0.5. This is the limit of precision of the color components
% of a pixel. Therefore, when alpha blending rounds to the nearest integer,
% no more accuracy is lost with OpenGL alpha blending than by calculating
% pixel values in MATLAB with floating point precision then rounding them
% to integer pixel values for display.
%
% Note that errors are cumulative and iterative alpha multiplication, in
% which a product of a prevoius multiplication becomes a factor in a
% subsequent multiplication, can produce large errors, even in the best
% case of rounding where 0 <= maximumError < 0.5. Note also that A single
% alpha blending operation may result in two multipliations, because both
% source and destination surfaces may be multiplied before they are added.
%
% We test blending accuracy becasue OpenGL makes no gurantees. The OpenGL
% policy on alpha multiplician is summarized here:
%
% http://msdn.microsoft.com/library/default.asp?url=/library/en-us/opengl/glfunc01_4vs3.asp
%
% "Despite the apparent precision of the above equations, blending
% arithmetic is not exactly specified, because blending operates with
% imprecise integer color values. However, a blend factor that should be
% equal to one is guaranteed not to modify its multiplicand, and a blend
% factor equal to zero reduces its multiplicand to zero."
%
% See also: AlphaBlendingTest, PsychAlphaBlending
% HISTORY
%
% mm/dd/yy
%
% 1/28/05 awi Wrote it.
% BUGS
%
% There is possibility that an OpenGL implementation would round
% multiplication to the nearest integer but have a different policy for
% which direction to round 0.5 than does MATLAB. In that case,
% TestAlphaMultiplicationAccuracy would return a maximumError of 0.5 and
% roundTypeStr 'unknown' instead of 'round'.
exitOnError= nargout < 1;
if nargin==0
screenNumber=max(Screen('Screens'));
end
%first test GetImage using PutImage because in later steps we rely on
%GetImage alpha blending.
background=127;
w=Screen('OpenWindow', screenNumber, [], [], [], 2);
Screen('FillRect', w, background);
wRect=Screen('Rect',w);
testPlane1=repmat(0:255, 256, 1);
testPlane2=rot90(testPlane1);
testImage1=repmat(testPlane1, [1, 1, 3]);
testImage2=repmat(testPlane2, [1,1,3]);
testImageRect=RectOfMatrix(testImage1);
imageMat1=testImage1;
imageMat1(:,:,4)=zeros(256);
zerosImage=repmat(zeros(256), [1,1,4]);
matRect=RectOfMatrix(testImage1);
sourceBlendFactors={ 'GL_ZERO', 'GL_ONE', 'GL_DST_COLOR', 'GL_ONE_MINUS_DST_COLOR', 'GL_SRC_ALPHA', 'GL_ONE_MINUS_SRC_ALPHA', 'GL_DST_ALPHA', 'GL_ONE_MINUS_DST_ALPHA', 'GL_SRC_ALPHA_SATURATE'};
destinationBlendFactors={'GL_ZERO','GL_ONE', 'GL_SRC_COLOR', 'GL_ONE_MINUS_SRC_COLOR', 'GL_SRC_ALPHA', 'GL_ONE_MINUS_SRC_ALPHA', 'GL_DST_ALPHA', 'GL_ONE_MINUS_DST_ALPHA'};
numSourceFactors=length(sourceBlendFactors);
numDestinationFactors=length(destinationBlendFactors);
sourceBlendVariableFactors={ 'GL_DST_COLOR', 'GL_ONE_MINUS_DST_COLOR', 'GL_SRC_ALPHA', 'GL_ONE_MINUS_SRC_ALPHA', 'GL_DST_ALPHA', 'GL_ONE_MINUS_DST_ALPHA', 'GL_SRC_ALPHA_SATURATE'};
destinationBlendVariableFactors={'GL_SRC_COLOR', 'GL_ONE_MINUS_SRC_COLOR', 'GL_SRC_ALPHA', 'GL_ONE_MINUS_SRC_ALPHA', 'GL_DST_ALPHA', 'GL_ONE_MINUS_DST_ALPHA'};
numSourceBlendVariableFactors=length(sourceBlendVariableFactors);
numDestinationBlendVariableFactors=length(destinationBlendVariableFactors);
% first, check that alpha multiplication gives the same result regardless of
% the mode. We do not test trivial cases of GL_ZERO and GL_ONE. Those are tested
% elsewhere, by TestAlphaMultiplication.
%for source blending
for i=1:numSourceBlendVariableFactors
%make source and destination images
[sourceImagesA{i}, destinationImagesA{i}]=SetSourceAlpha(sourceBlendVariableFactors{i}, testPlane2, imageMat1, zerosImage);
%write the destination matrix
Screen('BlendFunction', w, 'GL_ONE', 'GL_ZERO');
Screen('PutImage', w, destinationImagesA{i}, matRect);
%write the source matrix.
Screen('BlendFunction', w, sourceBlendVariableFactors{i}, 'GL_ZERO');
Screen('PutImage', w, sourceImagesA{i}, matRect);
sourceReadbacks{i}=Screen('GetImage',w,matRect);
Screen('Flip', w);
end
%compare results from every mode to results from every other.
sourceEqualityMat=zeros(numSourceBlendVariableFactors);
for i=1:numSourceBlendVariableFactors
for j=1:numSourceBlendVariableFactors
sourceEqualityMat(i,j)=isempty(find(sourceReadbacks{i}~=sourceReadbacks{j}));
end
end
%for destination blending
for i=1:numDestinationBlendVariableFactors
%make source and destination images
[sourceImagesB{i}, destinationImagesB{i}]=SetDestinationAlpha(destinationBlendVariableFactors{i}, testPlane2, zerosImage, imageMat1);
%write the destination matrix
Screen('BlendFunction', w, 'GL_ONE', 'GL_ZERO');
Screen('PutImage', w, destinationImagesB{i}, matRect);
%write the source matrix.
Screen('BlendFunction', w, 'GL_ZERO', destinationBlendVariableFactors{i});
Screen('PutImage', w, sourceImagesB{i}, matRect);
destinationReadbacks{i}=Screen('GetImage',w,matRect);
Screen('Flip', w);
end
%on the destination surface, for each mode compare the product to the products for
%every other mode and for each comparison store a bit into a table indicating a match.
destinationEqualityMat=zeros(numDestinationBlendVariableFactors);
for i=1:numDestinationBlendVariableFactors
for j=1:numDestinationBlendVariableFactors
destinationEqualityMat(i,j)=isempty(find(destinationReadbacks{i}~=destinationReadbacks{j}));
end
end
%on the source surface, for each mode compare the product to the products for
%every other mode and for each comparison store a bit into a table indicating a match.
sourceEqualityMat=zeros(numSourceBlendVariableFactors);
for i=1:numSourceBlendVariableFactors
for j=1:numSourceBlendVariableFactors
sourceEqualityMat(i,j)=isempty(find(sourceReadbacks{i}~=sourceReadbacks{j}));
end
end
%As above, but combine both source and destination results into a larger
%table indicating whether source surface product matches destination surface product.
allReadbacks={sourceReadbacks{:} destinationReadbacks{:}};
equalityMat=zeros(length(allReadbacks));
for i=1:length(allReadbacks)
for j=1:length(allReadbacks)
equalityMat(i,j)=isempty(find(allReadbacks{i}~=allReadbacks{j}));
end
end
%Test whether multliplication errors on the source surface are independent
%of the blending factor string
sourceIndependentFlag=isempty(find(sourceEqualityMat ~= 1));
%Test whether multliplication errors on the destination surface are independent
%of blending factor string
destinationIndependentFlag=isempty(find(destinationEqualityMat ~= 1));
%Test whether multliplication errors are independent of both the surface and the blending factor string
independentFlag=isempty(find(equalityMat ~= 1));
% whatever the multiplication accuracy, we now know from previous tests in
% this file if accuracy is the same for all modes. It should be,
% therefore, in the next step when testing that accuracy, we need only test
% one mode and know that those results apply to all others.
predictedReadbackAll=AlphaSourceTerm(sourceBlendVariableFactors{1}, sourceImagesA{1}, destinationImagesA{1});
predictedReadback=predictedReadbackAll(:,:,1:3);
maxFloatDiff=max(max(max(abs(predictedReadback-double(sourceReadbacks{1})))));
maxRoundDiff=max(max(max(abs(round(predictedReadback)-double(sourceReadbacks{1})))));
maxFloorDiff=max(max(max(abs(floor(predictedReadback)-double(sourceReadbacks{1})))));
maxCeilDiff=max(max(max(abs(ceil(predictedReadback)-double(sourceReadbacks{1})))));
maximumError=maxFloatDiff;
if maxRoundDiff==0
roundTypeStr='round';
elseif maxFloorDiff==0
roundTypeStr='floor';
elseif maxCeilDiff==0
roundTypeStr='ceil';
else
roundTypeStr='unknown';
end
Screen('CloseAll');
|