Hardware and software set up for 10-Bit stimuli

Hi Mario / Team,

Our goal is to measure contrast sensitivity functions of Gabor stimuli using the hardware and software detailed below. We wanted to be sure that we are producing 10-bit stimuli with this environment, in the way that our hardware and stimulus generation pipeline is set up correctly to support this. Do you recommend any extra steps we should take or corrections to the process? We really appreciate your advice on this.

We have purchased Psychtoolbox community membership with priority support (LMCU8-4M-20224131107:af2fcf3eb5ffbe76539789081d2aa4c010245de42f372e0ab0454475a41c1d4b).

Hardware
Monitor: Acer XB273U GX - 240/270Hz (OC) - 10-bit colour depth with temporal dithering. Running at 240hz with 10Bit colour depth selected.
Monitor settings
Brightness: 50
Contrast: 50
Black boost: off
G Sync: off
Overclock: off

PC: CPU – AMD Ryzen 7 3700X 8 Core, GPU – Nvidia GeForce RTX 2080 Super
OS: Windows 10 Home V21H2

Software
MATLAB version 2021b
Psychtoolbox version 3.0.18

Gamma correction
Screen gamma was linearised using Psychtoolbox CalibrateMonitorPhotometer.m
Photometer: Konica Minolta CS160 Luminance and colour meter
Mygammatable contains 256 values between 0 and 1 (On MS-Windows, only gamma
tables with 256 rows are accepted for the graphics card – is this ok?).
Gamma table is loaded using the Screen function.

[oldtable success] = Screen(‘LoadNormalizedGammaTable’, win, MygammaTable*[1 1 1]);

Screen set up
Done via PsychImaging Pipeline

PsychDefaultSetup(2);
PsychImaging(‘PrepareConfiguration’);
PsychImaging(‘AddTask’, ‘General’, ‘FloatingPoint32BitIfPossible’);
PsychImaging(‘AddTask’, ‘General’, ‘EnableNative10BitFramebuffer’ ,1);
PsychImaging(‘AddTask’, ‘General’, ‘NormalizedHighresColorRange’, 1);
PsychImaging(‘FinalizeConfiguration’);

Stimuli generation
Gabor stimuli are generated with the CreateProceduralGabor function and drawn with Screen DrawTextures.

backgroundOffset = [0.5 0.5 0.5 0.0];
disableNorm = 1;
preContrastMultiplier = 0.5;
gabortex = CreateProceduralGabor(win, g.dimPix, g.dimPix, , backgroundOffset, disableNorm, preContrastMultiplier);
.
.
.
Screen(‘BlendFunction’, win, GL_ONE, GL_ZERO);
Screen(‘DrawTextures’, win, gabortex, , g.position, g.orientation, , , , ,kPsychDontDoRotation, [g.phase, g.freq, g.sigma, g.contrast, g.aspectRatio, 0, 0, 0]');

How have we tested this so far?
Used the scripts TestBitDepth.m and AdditiveBlendingForLinearSuperpositionTutorial.m with the Output device in the script is set to Native10Bit.
Both of these scripts output similar results (see below).

AdditiveBlendingForLinearSuperpositionTutorial(‘Native10Bit’)
PTB-INFO: This is Psychtoolbox-3 for Microsoft Windows, under Matlab 64-Bit (Version 3.0.17 - Build date: Feb 4 2021).
PTB-INFO: OS support status: Windows 10 (Version 10.0) supported and tested to some limited degree.
PTB-INFO: Type ‘PsychtoolboxVersion’ for more detailed version information.
PTB-INFO: Most parts of the Psychtoolbox distribution are licensed to you under terms of the MIT License, with
PTB-INFO: some restrictions. See file ‘License.txt’ in the Psychtoolbox root folder for the exact licensing conditions.

PTB-INFO: For information about paid priority support, community membership and commercial services, please type
PTB-INFO: ‘PsychPaidSupportAndServices’.

PTB-INFO: Trying to enable at least 10 bpc fixed point framebuffer.
PTB-INFO: Windows native 10 bit per color framebuffer requested, and the OS claims it is working. Good.
PTB-INFO: Real (OS native, queried) color resolution of the GPU framebuffer is 10 bits per RGB color component.
PTB-INFO: The detected endline of the vertical blank interval is equal or lower than the startline. This indicates
PTB-INFO: that i couldn’t detect the duration of the vertical blank interval and won’t be able to correct timestamps
PTB-INFO: for it. This will introduce a very small and constant offset (typically << 1 msec). Read ‘help BeampositionQueries’
PTB-INFO: for how to correct this, should you really require that last few microseconds of precision.
PTB-INFO: Btw. this can also mean that your systems beamposition queries are slightly broken. It may help timing precision to
PTB-INFO: enable the beamposition workaround, as explained in ‘help ConserveVRAMSettings’, section ‘kPsychUseBeampositionQueryWorkaround’.

PTB-INFO: OpenGL-Renderer is NVIDIA Corporation :: GeForce RTX 2080 SUPER/PCIe/SSE2 :: 4.6.0 NVIDIA 457.51
PTB-INFO: VBL startline = 1440 , VBL Endline = 1439
PTB-INFO: Measured monitor refresh interval from beamposition = 4.168535 ms [239.892450 Hz].
PTB-INFO: Will use beamposition query for accurate Flip time stamping.
PTB-INFO: Measured monitor refresh interval from VBLsync = 4.166530 ms [240.007872 Hz]. (50 valid samples taken, stddev=0.004792 ms.)
PTB-INFO: Reported monitor refresh interval from operating system = 4.166667 ms [240.000000 Hz].
PTB-INFO: Small deviations between reported values are normal and no reason to worry.
PTB-INFO: ==============================================================================================================================
PTB-INFO: WINDOWS DWM DESKTOP COMPOSITOR IS ACTIVE. On this Windows-10 or later system, Psychtoolbox can no longer reliably detect if
PTB-INFO: this will cause trouble for timing and integrity of visual stimuli or not. You might be just fine, or you could be in trouble.
PTB-INFO: Use external measurement equipment and independent procedures to verify reliability of timing if you care about proper timing.
PTB-INFO: ==============================================================================================================================
PTB-INFO: Psychtoolbox imaging pipeline starting up for window with requested imagingmode 5125 …
PTB-INFO: Will use 32 bits per color component floating point framebuffer for stimulus drawing. Alpha blending should work correctly.
PTB-INFO: Will use 32 bits per color component floating point framebuffer for stimulus post-processing (if any).
Building a fragment shader:Reading shader from file C:\Program Files\MATLAB\Psychtoolbox\PsychOpenGL/PsychGLSLShaders/ICMSimpleGammaCorrectionShader.frag.txt …
Average redraw rate in demo was 81.115598 Hz.
Average update rate in pipeline was 239.198422 Hz.

These scripts were also run using output device = “Native11Bit” and it errored. Which we took as a good sign.

We have also run the BitsPlusCSFDemo.m
When running the code there is a clear difference between 8 and 10 bit mode, with no obvious banding or aliasing.

Mario can give you the details about the 256 value gamma table limitation on Windows (Linux doesn’t have that limit by the way), but the one extra thing I did was to make a small script that changes luminance in 1 / 2^10 steps, and double check with the photometer for each step a consistent increase in luminance is observed (a staircase). This confirms that the PTB+GPU+Monitor display pipeline is working at the luminance limit it is supposed to…

I am not sure if this applies to NVidia cards on Windows, as we do not recommend NVidia in general, and very little testing is done with NVidia. But maybe good to check:
Did you select these 10 bit also in the NVidia display driver setup GUI? There may be settings in there for each connected display to specify for a connected display the output signal precision and if dithering is enabled. If so, you would want to make sure it is 10 bit and that dithering by the graphics card itself is off. Otherwise you may get an 8 bit signal with dithering to 10 bit applied by the graphics card, which may or may not of the same quality as if the display itself does its native 10 bit input.

Could be that no such settings exist on Windows though, and only the Linux NVidia driver has these settings. It is actually news to me that NVidia allows 10 bit output on some consumer GeForce cards at all on Windows - so far this feature was reserved to Linux only. But all of PTB’s outputs and your results suggest this is now supported at least on your consumer GeForce RTX 2080.

That should be fine. Windows only allows 256 slot input gamma tables with the api’s we can use atm… I think what Windows drivers do is take the 256 slot lut from PTB and internally fit a finer granularity gamma function to the provided data and then load that best-fit lut into the hardware lut’s. E.g., typically piece-wise linear functions to setup a 1024 or 4096 slot lut. At least various modern AMD and Intel gpu’s do not even use discrete lut’s anymore. They implement such piece-wise linear functions in hardware and configure them to be a best fit to the user provided lut, depending on mode of operation and gpu model.

I’d leave the last ‘FinalizeConfiguration’ call out - it is for expert use only, and a simple PsychImaging('OpenWindow', ...) at that point will do the trick, as shown in our demos and tests. The rest is fine.

All the further steps and output looks fine to me. What Ian says makes sense as another verification step. We do have the test script MeasureLuminancePrecision which would automate such a verification with supported photometers, but unfortunately your Minolta device is not one of the supported models for automatic measurement and verification, so that won’t help.

In general, the best tested (by myself with a CRS ColorCal2) and most powerful setup for such high precision stimuli is modern Linux with a modern AMD graphics card, where one can achieve up to 12 bit of precision per color channel on current hw generations.

-mario