File: SCREENGetWindowInfo.c

package info (click to toggle)
psychtoolbox-3 3.0.19.14.dfsg1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 86,796 kB
  • sloc: ansic: 176,245; cpp: 20,103; objc: 5,393; sh: 2,753; python: 1,397; php: 384; makefile: 193; java: 113
file content (717 lines) | stat: -rw-r--r-- 42,525 bytes parent folder | download
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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
/*
  SCREENGetWindowInfo.c

  AUTHORS:

  mario.kleiner.de@gmail.com  mk

  PLATFORMS:    All

  HISTORY:
  06/03/07      mk  Created.

  DESCRIPTION:

  Returns all kind of misc information about a specific window in a struct.
  This is a catch-all for information that's not of too much interest for regular
  users, but useful for Psychtoolbox helper functions (M-Files).

  NOTES:

  Be careful with length of struct field names! Only names up to 31 characters are
  supported by Matlab 5.x (and maybe 6.x -- untested). Larger names cause matching
  failure!
*/

#include "Screen.h"

#if PSYCH_SYSTEM == PSYCH_OSX

/* This function defines of Apple undocumented functions are taken from CGSDebug.h, a
 * file provided by Alacatia Labs. This is the copyright info associated with it:
 *
 * Routines for debugging the window server and application drawing.
 *
 * Copyright (C) 2007-2008 Alacatia Labs
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 *
 * Joe Ranieri joe@alacatia.com
 *
 *
 */

typedef enum {
	/*! Clears all flags. */
	kCGSDebugOptionNone = 0,

	/*! All screen updates are flashed in yellow. Regions under a DisableUpdate are flashed in orange. Regions that are hardware accellerated are painted green. */
	kCGSDebugOptionFlashScreenUpdates = 0x4,

	/*! Colors windows green if they are accellerated, otherwise red. Doesn't cause things to refresh properly - leaves excess rects cluttering the screen. */
	kCGSDebugOptionColorByAccelleration = 0x20,

	/*! Disables shadows on all windows. */
	kCGSDebugOptionNoShadows = 0x4000,

	/*! Setting this disables the pause after a flash when using FlashScreenUpdates or FlashIdenticalUpdates. */
	kCGSDebugOptionNoDelayAfterFlash = 0x20000,

	/*! Flushes the contents to the screen after every drawing operation. */
	kCGSDebugOptionAutoflushDrawing = 0x40000,

	/*! Highlights mouse tracking areas. Doesn't cause things to refresh correctly - leaves excess rectangles cluttering the screen. */
	kCGSDebugOptionShowMouseTrackingAreas = 0x100000,

	/*! Flashes identical updates in red. */
	kCGSDebugOptionFlashIdenticalUpdates = 0x4000000,

	/*! Dumps a list of windows to /tmp/WindowServer.winfo.out. This is what Quartz Debug uses to get the window list. */
	kCGSDebugOptionDumpWindowListToFile = 0x80000001,

	/*! Dumps a list of connections to /tmp/WindowServer.cinfo.out. */
	kCGSDebugOptionDumpConnectionListToFile = 0x80000002,

	/*! Dumps a very verbose debug log of the WindowServer to /tmp/CGLog_WinServer_<PID>. */
	kCGSDebugOptionVerboseLogging = 0x80000006,

	/*! Dumps a very verbose debug log of all processes to /tmp/CGLog_<NAME>_<PID>. */
	kCGSDebugOptionVerboseLoggingAllApps = 0x80000007,

	/*! Dumps a list of hotkeys to /tmp/WindowServer.keyinfo.out. */
	kCGSDebugOptionDumpHotKeyListToFile = 0x8000000E,

	/*! Dumps information about OpenGL extensions, etc to /tmp/WindowServer.glinfo.out. */
	kCGSDebugOptionDumpOpenGLInfoToFile = 0x80000013,

	/*! Dumps a list of shadows to /tmp/WindowServer.shinfo.out. */
	kCGSDebugOptionDumpShadowListToFile = 0x80000014,

	/*! Leopard: Dumps information about caches to `/tmp/WindowServer.scinfo.out`. */
	kCGSDebugOptionDumpCacheInformationToFile = 0x80000015,

	/*! Leopard: Purges some sort of cache - most likely the same caches dummped with `kCGSDebugOptionDumpCacheInformationToFile`. */
	kCGSDebugOptionPurgeCaches = 0x80000016,

	/*! Leopard: Dumps a list of windows to `/tmp/WindowServer.winfo.plist`. This is what Quartz Debug on 10.5 uses to get the window list. */
	kCGSDebugOptionDumpWindowListToPlist = 0x80000017,

	/*! Leopard: DOCUMENTATION PENDING */
	kCGSDebugOptionEnableSurfacePurging = 0x8000001B,

	// Leopard: 0x8000001C - invalid

	/*! Leopard: DOCUMENTATION PENDING */
	kCGSDebugOptionDisableSurfacePurging = 0x8000001D,

	/*! Leopard: Dumps information about an application's resource usage to `/tmp/CGResources_<NAME>_<PID>`. */
	kCGSDebugOptionDumpResourceUsageToFiles = 0x80000020,

	// Leopard: 0x80000022 - something about QuartzGL?

	// Leopard: Returns the magic mirror to its normal mode. The magic mirror is what the Dock uses to draw the screen reflection. For more information, see `CGSSetMagicMirror`. */
	kCGSDebugOptionSetMagicMirrorModeNormal = 0x80000023,

	/*! Leopard: Disables the magic mirror. It still appears but draws black instead of a reflection. */
	kCGSDebugOptionSetMagicMirrorModeDisabled = 0x80000024,
} CGSDebugOption;

typedef int CGSConnectionID;
extern CGSConnectionID _CGSDefaultConnection(void);
extern CGError CGSGetPerformanceData(CGSConnectionID cid, float *outFPS, float *unk, float *unk2, float *unk3);
extern CGError CGSSetDebugOptions(int options);
extern int CGSGetDebugOptions(int *outCurrentOptions);

#endif

static char useString[] = "info = Screen('GetWindowInfo', windowPtr [, infoType=0] [, auxArg1]);";
static char synopsisString[] =
    "Returns a struct with miscellaneous info for the specified onscreen window.\n\n"
    "\"windowPtr\" is the handle of the onscreen window for which info should be returned.\n\n"
    "\"infoType\" If left out or set to zero, all available information for the 'windowPtr' is returned.\n\n"
    "If set to -1, only the OpenGL context of the onscreen window is activated (Expert use only!).\n\n"
    "If set to 1, only the rasterbeam position of the associated display device is returned (or -1 if unsupported).\n\n"
    "If set to 2, information about the window server is returned (or -1 if unsupported).\n\n"
    "If set to 3, low-level window server settings are changed according to 'auxArg1'. Do *not* use, "
    "unless you really know what you're doing and have read the relevant PTB source code!\n\n"
    "If set to 4, returns a single value with the current activity status of asynchronous flips. "
    "1 if a Screen('AsyncFlipBegin') was called and the flip is still active, ie., hasn't "
    "been finished with a matching Screen('AsyncFlipEnd') or Screen('AsyncFlipCheckEnd');, zero otherwise."
    "You can call this function with an infoType of zero only if no async flips are active, or if the "
    "imaging pipeline is fully enabled. This is why you need to use the special infoType 4 to find "
    "out if async flips are active.\n\n"
    "If set to 5, will start measurement of GPU time for render operations. The clock will start "
    "on the next drawing command after this call. The clock will by default stop at the next call to "
    "Screen('Flip'), Screen('AsyncFlipBegin'), or Screen('DrawingFinished'). Measured time will "
    "include all the time spent by the GPU for preparing the final visual stimulus image for the next "
    "flip, including all post-processing operations performed by the imaging pipeline.\n\n"
    "If you want to exclude time spent in image post-processing or just measure the time spent for "
    "a defined set of drawing commands, you can stop the clock earlier by calling this function with "
    "infoType set to 6. In that case, only GPU time spent between the infoType=5 call and the infoType=6 "
    "call will be reported, excluding any later drawing commands or imaging pipeline post-processing.\n\n"
    "After the measured GPU operations complete, the elapsed rendertime will be returned in the 'GPULastFrameRenderTime' "
    "field of the struct that you get when calling with infoType=0.\n"
    "Due to the asynchronous nature of GPU rendering, the measured time may not be immediately "
    "available after the clock is stopped. In this case, 'GPULastFrameRenderTime' will be zero and "
    "you will need to repeat the infoType=0 query later.\n"
    "Please note that not all GPU's and operating systems support this function. If the "
    "function is unsupported, a value of zero will be returned in the info struct and by any call "
    "with 'infoType' of 5 or 6.\n\n"
    "An 'infoType' of 7 does return the same information as the default 'infoType' 0, but does not "
    "set the window 'windowPtr' as drawing target, does not activate its OpenGL context and only "
    "returns information that is safe to return without setting the window as drawing target.\n\n"
    "An 'infoType' of 8 returns 1 if the X-Screens primary gpu uses the modesetting-ddx under Linux.\n\n"
    "An 'infoType' of 9 returns a struct with interop info needed for interop with certain clients, "
    "currently tailored to the needs of OpenGL interop with the OpenXR api on Linux and Windows.\n\n"
    "\n"
    "The default info struct for 'infoType' 7 and the default 'infoType' 0 contains all kinds of information. "
    "Just check its output to see what is returned. Most of this info is not interesting for normal users, "
    "mostly provided for internal use by M-Files belonging to Psychtoolbox itself, e.g., display tests.\n\n"
    "The info struct contains the following fields:\n"
    "----------------------------------------------\n\n"
    "Beamposition: Current rasterbeam position of the video scanout cycle.\n"
    "LastVBLTimeOfFlip: VBL timestamp of last finished Screen('Flip') operation.\n"
    "TimeAtSwapRequest: Timestamp taken prior to submission of the low-level swap command. Useful for micro-benchmarking.\n"
    "TimePostSwapRequest: Timestamp taken after submission of the low-level swap command. Useful for micro-benchmarking.\n"
    "VBLTimePostFlip: Optional flip completion timestamp from VBLANK timestamping. Useful for micro-benchmarking.\n"
    "OSSwapTimestamp: Optional flip completion timestamp from OS-Builtin timestamping. Useful for micro-benchmarking.\n"
    "GPULastFrameRenderTime: Duration of all rendering operations, as measured by GPU, if infoType=5 was used.\n"
    "RawSwapTimeOfFlip: Raw (uncorrected by high-precision timestamping) timestamp of last finished Screen('Flip') operation.\n"
    "LastVBLTime: System time when last vertical blank happened, or the same as "
    "LastVBLTimeOfFlip if the system doesn't support queries of this property (currently only OS/X does.)\n"
    "VBLCount: Running count of vertical blank intervals since (graphics)system startup. Or zero if not"
    "supported by system. Currently only OS/X and Linux do support this with some GPU's.\n"
    "VideoRefreshFromBeamposition: Estimate of video refresh cycle from beamposition measurement method.\n"
    "GLVendor, GLRenderer, GLVersion: Vendor name, renderer name and version of the OpenGL implementation.\n"
    "GLDeviceUUID: The unique device id if supported by the OpenGL implementation, an empty field otherwise.\n"
    "StereoMode: Currently selected stereomode, as requested in call to Screen('OpenWindow', ...);\n"
    "StereoDrawBuffer: Current drawbuffer for stereo display (0 = left eye, 1 = right eye, 2 = None in mono mode).\n"
    "ImagingMode: Currently selected imging pipeline mode, as requested in call to Screen('OpenWindow', ...);\n"
    "MultiSampling: Currently selected multisample anti-aliasing mode, as requested in call to Screen('OpenWindow', ...);\n"
    "MissedDeadlines: Number of missed Screen('Flip') stimulus onset deadlines, according to internal skip detector.\n"
    "FlipCount: Total number of flip command executions, ie., of stimulus updates.\n"
    "GuesstimatedMemoryUsageMB: Estimated memory usage of window or texture in Megabytes. Can be very inaccurate or unavailable!\n"
    "VBLStartLine, VBLEndline: Start/Endline of vertical blanking interval. The VBLEndline value is not available/valid on all GPU's.\n"
    "SwapGroup: Swap group id of the swap group to which this window is assigned. Zero for none.\n"
    "SwapBarrier: Swap barrier id of the swap barrier to which this windows swap group is assigned. Zero for none.\n"
    "SysWindowHandle: Low-level windowing system specific window handle of the onscreen window.\n"
    "SysWindowInteropHandle: Low-level windowing system specific window-related auxiliary handle of the onscreen window.\n"
    "ExternalMouseMultFactor: Scaling factor to apply for remapping input coordinates on some systems, e.g., by RemapMouse.m.\n"
    "VRRMode: Actual selected mode for VRR stimulus onset scheduling (1 = auto maps to actual choice): 0 = Off, 2 = Simple, 3 = OwnScheduled.\n"
    "VRRStyleHint: Style hint code for the current active VRR stimulation timing style, ie. what is assumed about timing behaviour of the paradigm.\n"
    "VRRLatencyCompensation: Current estimate of average VRR swapbuffers latency, used for compensating during VRR scheduling in 'OwnScheduled' mode.\n"
    "\n"
    "The following settings are derived from a builtin detection heuristic, which works on most common GPU's:\n\n"
    "GPUCoreId: Symbolic name string that roughly describes the name of the GPU core of the graphics card. This string is arbitrarily\n"
    "chosen to roughly group the cores by common capabilities (and quirks). Currently defined are:\n"
    "R100 = Very old ATI GPUs, R300 = GPU's roughly starting at Radeon 9000, R500 = Radeon X1000 or later, R600 = Radeon HD2000 or later.\n"
    "NV10 = Very old NVidia GPUs, NV30 = NV30 or later, NV40 = Geforce6000/7000 or later, G80 = Geforce8000 or later.\n"
    "An empty GPUCoreId string means a different, unspecified core.\n\n"
    "DisplayCoreId: Vendor of the display engine / display gpu, NVidia, AMD, Intel, or same as 'GPUCoreId'. May differ from 'GPUCoreId' in hybrid graphics laptops.\n"
    "BitsPerColorComponent: Effective color depths of window/framebuffer in bits per color channel component (bpc).\n"
    "GLSupportsFBOUpToBpc: 0 = No support for framebuffer objects. Otherwise maximum supported bpc (8, 16, 32).\n"
    "GLSupportsBlendingUpToBpc: Maximum supported bpc for hardware accelerated framebuffer blending (alpha blending).\n"
    "GLSupportsTexturesUpToBpc: Maximum supported bpc for textures (8, 16, 32).\n"
    "GLSupportsFilteringUpToBpc: Maximum supported bpc for hardware accelerated linear filtering of textures (8, 16, 32).\n"
    "GLSupportsPrecisionColors: 1 = Hardware can be fully trusted to rasterize perfect 32 bpc colors in floating point color mode "
    "without special support of PTB. 0 = Needs special (slower) support from PTB to work.\n"
    "GLSupportsFP32Shading: 1 = All internal calculations of the GPU are done with IEEE single precision 32 bit floating point, i.e., "
    "very accurate.\n"
    "GPUMinorType: Numeric vendor specific gpu id. Chip family on NVidia, display engine revision on AMD atm. -1 if unknown. Subject to change without notice!\n\n";

static char seeAlsoString[] = "OpenWindow, Flip, NominalFrameRate";

PsychError SCREENGetWindowInfo(void)
{
    const char *FieldNames[]={ "Beamposition", "LastVBLTimeOfFlip", "LastVBLTime", "VBLCount", "TimeAtSwapRequest", "TimePostSwapRequest", "RawSwapTimeOfFlip",
                                "VBLTimePostFlip", "OSSwapTimestamp", "GPULastFrameRenderTime", "StereoMode", "ImagingMode", "MultiSampling", "MissedDeadlines", "FlipCount", "StereoDrawBuffer",
                                "GuesstimatedMemoryUsageMB", "VBLStartline", "VBLEndline", "VideoRefreshFromBeamposition", "GLVendor", "GLRenderer", "GLVersion", "GPUCoreId", "GPUMinorType",
                                "DisplayCoreId", "GLSupportsFBOUpToBpc", "GLSupportsBlendingUpToBpc", "GLSupportsTexturesUpToBpc", "GLSupportsFilteringUpToBpc", "GLSupportsPrecisionColors",
                                "GLSupportsFP32Shading", "BitsPerColorComponent", "IsFullscreen", "SpecialFlags", "SwapGroup", "SwapBarrier", "SysWindowHandle", "ExternalMouseMultFactor", "VRRMode",
                                "VRRStyleHint", "VRRLatencyCompensation", "GLDeviceUUID", "SysWindowInteropHandle" };
    const int fieldCount = 44;
    PsychGenericScriptType *s;

    PsychWindowRecordType *windowRecord;
    double beamposition, lastvbl;
    int infoType = 0;
    double auxArg1, auxArg2, auxArg3;
    CGDirectDisplayID displayId;
    psych_uint64 postflip_vblcount;
    psych_bool onscreen;
    int queryState;
    unsigned int gpuTimeElapsed;
    int gpuMaintype, gpuMinorType;

    //all subfunctions should have these two lines.
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

    PsychErrorExit(PsychCapNumInputArgs(5));     //The maximum number of inputs
    PsychErrorExit(PsychRequireNumInputArgs(1)); //The required number of inputs
    PsychErrorExit(PsychCapNumOutputArgs(1));    //The maximum number of outputs

    // Query infoType flag: Defaults to zero.
    PsychCopyInIntegerArg(2, FALSE, &infoType);
    if (infoType < -1 || infoType > 9) PsychErrorExitMsg(PsychError_user, "Invalid 'infoType' argument specified! Valid are -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.");

    // Windowserver info requested?
    if (infoType == 2 || infoType == 3) {
        // Return info about WindowServer:
        #if PSYCH_SYSTEM == PSYCH_OSX

        const char *CoreGraphicsFieldNames[]={ "CGSFps", "CGSValue1", "CGSValue2", "CGSValue3", "CGSDebugOptions" };
        const int CoreGraphicsFieldCount = 5;
        float cgsFPS, val1, val2, val3;
        int retIntArg;

        // This (undocumented) Apple call retrieves information about performance statistics of
        // the Core graphics server, also known as WindowServer or Quartz compositor:
        CGSGetPerformanceData(_CGSDefaultConnection(), &cgsFPS, &val1, &val2, &val3);
        if (CGSGetDebugOptions(&retIntArg)) {
            if (PsychPrefStateGet_Verbosity() > 1) printf("PTB-WARNING: GetWindowInfo: Call to CGSGetDebugOptions() failed!\n");
        }

        PsychAllocOutStructArray(1, FALSE, -1, CoreGraphicsFieldCount, CoreGraphicsFieldNames, &s);
        PsychSetStructArrayDoubleElement("CGSFps", 0   , cgsFPS, s);
        PsychSetStructArrayDoubleElement("CGSValue1", 0, val1, s);
        PsychSetStructArrayDoubleElement("CGSValue2", 0, val2, s);
        PsychSetStructArrayDoubleElement("CGSValue3", 0, val3, s);
        PsychSetStructArrayDoubleElement("CGSDebugOptions", 0, (double) retIntArg, s);

        if ( (infoType == 3) && PsychCopyInDoubleArg(3, FALSE, &auxArg1) ) {
            // Type 3 setup request with auxArg1 provided. Apple auxArg1 as debugFlag setting
            // for the CoreGraphics server: DANGEROUS!
            if (CGSSetDebugOptions((unsigned int) auxArg1)) {
                if (PsychPrefStateGet_Verbosity() > 1) printf("PTB-WARNING: GetWindowInfo: Call to CGSSetDebugOptions() failed!\n");
            }
        }

        #endif

        #if PSYCH_SYSTEM == PSYCH_WINDOWS
        psych_uint64 onsetVBLCount, frameId;
        double onsetVBLTime, compositionRate;
        psych_uint64 targetVBL;

        PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
        // Query all DWM presentation timing info, return full info as struct in optional return argument '1':
        if (PsychOSGetPresentationTimingInfo(windowRecord, TRUE, 0, &onsetVBLCount, &onsetVBLTime, &frameId, &compositionRate, 1)) {
            // Query success: Info struct has been created and returned by PsychOSGetPresentationTimingInfo()...
            auxArg1 = auxArg2 = 0;
            auxArg3 = 2;

            // Want us to change settings?
            if ( (infoType == 3) && PsychCopyInDoubleArg(3, FALSE, &auxArg1) && PsychCopyInDoubleArg(4, FALSE, &auxArg2) && PsychCopyInDoubleArg(5, FALSE, &auxArg3)) {
                if (auxArg1 < 0) auxArg1 = 0;
                targetVBL = (psych_uint64) auxArg1;
                if (PsychOSSetPresentParameters(windowRecord, targetVBL, (int) auxArg3, auxArg2)) {
                    if (PsychPrefStateGet_Verbosity() > 5) printf("PTB-DEBUG: GetWindowInfo: Call to PsychOSSetPresentParameters(%i, %i, %f) SUCCESS!\n", (int) auxArg1, (int) auxArg3, auxArg2);
                }
                else {
                    if (PsychPrefStateGet_Verbosity() > 1) printf("PTB-WARNING: GetWindowInfo: Call to PsychOSSetPresentParameters() failed!\n");
                }
            }
        }
        else {
            // Unsupported / Failed:
            PsychCopyOutDoubleArg(1, FALSE, -1);
        }

        #endif

        #if PSYCH_SYSTEM == PSYCH_LINUX
            if (infoType == 2) {
                // MMIO register Read for screenid "auxArg1", register offset "auxArg2":
                PsychCopyInDoubleArg(3, TRUE, &auxArg1);
                PsychCopyInDoubleArg(4, TRUE, &auxArg2);
                PsychCopyOutDoubleArg(1, FALSE, (double) PsychOSKDReadRegister((int) auxArg1, (unsigned int) auxArg2, NULL));
            }

            if (infoType == 3) {
                // MMIO register Write for screenid "auxArg1", register offset "auxArg2", to value "auxArg3":
                PsychCopyInDoubleArg(3, TRUE, &auxArg1);
                PsychCopyInDoubleArg(4, TRUE, &auxArg2);
                PsychCopyInDoubleArg(5, TRUE, &auxArg3);
                PsychOSKDWriteRegister((int) auxArg1, (unsigned int) auxArg2, (unsigned int) auxArg3, NULL);
            }
        #endif

        // Done.
        return(PsychError_none);
    }

    // Get the window record:
    PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
    onscreen = PsychIsOnscreenWindow(windowRecord);

    // Only want windows OpenGL context activated?
    if (infoType == -1) {
        PsychSetGLContext(windowRecord);
        return(PsychError_none);
    }

    if (onscreen) {
        // Query rasterbeam position: Will return -1 if unsupported.
        PsychGetCGDisplayIDFromScreenNumber(&displayId, windowRecord->screenNumber);
        beamposition = (double) PsychGetDisplayBeamPosition(displayId, windowRecord->screenNumber);
    }
    else {
        beamposition = -1;
    }

    if (infoType == 1) {
        // Return the measured beamposition:
        PsychCopyOutDoubleArg(1, FALSE, beamposition);
    }
    else if (infoType == 4) {
        // Return async flip state: 1 = Active, 0 = Inactive.
        PsychCopyOutDoubleArg(1, FALSE, (((NULL != windowRecord->flipInfo) && (0 != windowRecord->flipInfo->asyncstate)) ? 1 : 0));
    }
    else if (infoType == 5) {
        if (!PsychIsOnscreenWindow(windowRecord)) {
            PsychErrorExitMsg(PsychError_user, "Tried to create a GPU rendertime query on a texture or offscreen window. Only supported on onscreen windows!");
        }

        // Only need OpenGL mastercontext, not full drawingtarget:
        PsychSetGLContext(windowRecord);

        // Create a GL_EXT_timer_query object for this window:
        if (glewIsSupported("GL_EXT_timer_query")) {
            // Pending queries finished?
            if (windowRecord->gpuRenderTimeQuery > 0) {
                PsychErrorExitMsg(PsychError_user, "Tried to create a new GPU rendertime query, but last query not yet finished! Call Screen('Flip') first!");
            }

            // Generate Query object:
            glGenQueries(1, &windowRecord->gpuRenderTimeQuery);

            // Emit Query: GPU will measure elapsed processing time in Nanoseconds, starting
            // with the first GL command executed after this command:
            glBeginQuery(GL_TIME_ELAPSED_EXT, windowRecord->gpuRenderTimeQuery);

            // Reset last measurement:
            windowRecord->gpuRenderTime = 0;

            // Report status "in progress" = 1:
            PsychCopyOutDoubleArg(1, FALSE, 1);
        }
        else {
            if (PsychPrefStateGet_Verbosity() > 4) printf("PTB-INFO: GetWindowInfo for infoType 5: GPU timer query objects are unsupported on this platform and GPU. Call ignored!\n");
            // Report status "unsupported" = 0:
            PsychCopyOutDoubleArg(1, FALSE, 0);
        }
    }
    else if (infoType == 6) {
        if (!PsychIsOnscreenWindow(windowRecord)) {
            PsychErrorExitMsg(PsychError_user, "Tried to finish a GPU rendertime query on a texture or offscreen window. Only supported on onscreen windows!");
        }

        // End time measurement for any previously submitted rendering commands if a
        // GPU rendertime query was requested, otherwise just no-op:
        if (windowRecord->gpuRenderTimeQuery) {
            // Only need OpenGL mastercontext, not full drawingtarget:
            PsychSetGLContext(windowRecord);

            // Unfinished query? If so, finish it.
            glGetQueryiv(GL_TIME_ELAPSED_EXT, GL_CURRENT_QUERY, &queryState);
            if (queryState > 0) glEndQuery(GL_TIME_ELAPSED_EXT);
        }

        // Report if a query was pending:
        PsychCopyOutDoubleArg(1, FALSE, (windowRecord->gpuRenderTimeQuery) ? 1 : 0);
    }
    else if (infoType == 8) {
        // Modesetting ddx on Linux X11 in use?
        #if PSYCH_SYSTEM == PSYCH_LINUX
            PsychCopyOutDoubleArg(1, FALSE, PsychOSX11ScreenUsesModesettingDDX(windowRecord->screenNumber));
        #else
            PsychErrorExitMsg(PsychError_unimplemented, "infoType 8 query is only supported on Linux.");
        #endif
    }
    else if (infoType == 9) {
        // Interop info for special external clients, with which we want to share OpenGL contexts and textures, e.g., OpenXR:
        const char* FieldNamesInterop[] = { "DeviceContext", "OpenGLContext", "OpenGLContextScreen", "OpenGLDrawable", "OpenGLConfig", "OpenGLVisualId" };
        const int fieldCountInterop = 6;

        // This gives access to the OpenGL context and associated drawable, resources and config of our parallel background flipperThread.
        // Normally the flipperThread would use these to implement special functionality like async flips, vrr, framesequential stereo etc.
        // Here the idea is to usually not use the flipperThread, but instead piggyback on / (ab-)use the OpenGL resources normally used
        // for that thread for other purposes, e.g., interop with special external components like the PsychOpenXRCore driver and OpenXR.
        // Note: For purely single-thread operations without a dedicated context for external use, we also expose Screen's main OpenGL context.

        PsychAllocOutStructArray(1, FALSE, -1, fieldCountInterop, FieldNamesInterop, &s);
        PsychSetStructArrayUnsignedInt64Element("DeviceContext", 0, (psych_uint64) (size_t) windowRecord->targetSpecific.deviceContext, s);
        PsychSetStructArrayUnsignedInt64Element("OpenGLContext", 0, (psych_uint64) (size_t) windowRecord->targetSpecific.glswapcontextObject, s);
        PsychSetStructArrayUnsignedInt64Element("OpenGLContextScreen", 0, (psych_uint64) (size_t) windowRecord->targetSpecific.contextObject, s);
        PsychSetStructArrayUnsignedInt64Element("OpenGLDrawable", 0, (psych_uint64) (size_t) windowRecord->targetSpecific.windowHandle, s);
        #if (PSYCH_SYSTEM == PSYCH_LINUX) && !defined(PTB_USE_WAFFLE) && !defined(PTB_USE_WAYLAND)
            // Linux X11/GLX/Xlib only:
            PsychSetStructArrayUnsignedInt64Element("OpenGLConfig", 0, (psych_uint64) (size_t) windowRecord->targetSpecific.pixelFormatObject, s);
            PsychSetStructArrayUnsignedInt64Element("OpenGLVisualId", 0, (psych_uint64) (size_t) windowRecord->targetSpecific.visualId, s);
        #else
            PsychSetStructArrayUnsignedInt64Element("OpenGLConfig", 0, (psych_uint64) (size_t) 0, s);
            PsychSetStructArrayUnsignedInt64Element("OpenGLVisualId", 0, (psych_uint64) (size_t) 0, s);
        #endif
    }
    else {
        // Set OpenGL context (always needed) and drawing target, as setting
        // our windowRecord as a drawingtarget is an expected side-effect of
        // this function. Quite a bit of PTB M-Functions and usercode rely on
        // this. Exception is infoType 7 which asks to omit this call:
        if (infoType != 7) {
            // Only set as drawing target if it can act as a drawing target ie. onscreen/offscreen/texture.
            // Proxywindows like GLOperators() are derived from windows but can't be used as drawing target,
            // so only set their OpenGL context:
            if (PsychIsOnscreenWindow(windowRecord) || PsychIsOffscreenWindow(windowRecord))
                PsychSetDrawingTarget(windowRecord);
            else
                PsychSetGLContext(windowRecord);
        }

        // Return all information:
        PsychAllocOutStructArray(1, FALSE, -1, fieldCount, FieldNames, &s);

        // Rasterbeam position:
        PsychSetStructArrayDoubleElement("Beamposition", 0, beamposition, s);

        // Time of last vertical blank when a double-buffer swap occured:
        if ((windowRecord->flipCount > 0) && (windowRecord->time_at_last_vbl == 0) && !(windowRecord->specialflags & kPsychSkipTimestampingForFlipOnce) &&
            (PsychPrefStateGet_VBLTimestampingMode() == 4)) {
            // If time_at_last_vbl for an already finished or at least pending flip isn't available and
            // we have support for OS-Builtin timestamping enabled, we try to employ OS-Builtin timestamping
            // to get a timestamp for the most recent pending or finished flip. If this fails or is unsupported,
            // it will have no effect:
            PsychOSGetSwapCompletionTimestamp(windowRecord, 0, &(windowRecord->time_at_last_vbl));
        }

        // Return it - or the value zero if it is (still) undefined/unavailable:
        PsychSetStructArrayDoubleElement("LastVBLTimeOfFlip", 0, windowRecord->time_at_last_vbl, s);

        // Uncorrected timestamp of flip swap completion:
        PsychSetStructArrayDoubleElement("RawSwapTimeOfFlip", 0, windowRecord->rawtime_at_swapcompletion, s);

        // Timestamp immediately prior to call to PsychOSFlipWindowBuffers(), i.e., time at swap request submission:
        PsychSetStructArrayDoubleElement("TimeAtSwapRequest", 0, windowRecord->time_at_swaprequest, s);

        // Timestamp immediately after call to PsychOSFlipWindowBuffers() returns, i.e., time at swap request submission completion:
        PsychSetStructArrayDoubleElement("TimePostSwapRequest", 0, windowRecord->time_post_swaprequest, s);

        // Timestamp immediately after call to PsychOSFlipWindowBuffers() returns, i.e., time at swap request submission completion:
        PsychSetStructArrayDoubleElement("VBLTimePostFlip", 0, windowRecord->postflip_vbltimestamp, s);

        // Swap completion timestamp for most recently completed swap, according to OS-builtin PsychOSGetSwapCompletionTimestamp() method:
        PsychSetStructArrayDoubleElement("OSSwapTimestamp", 0, windowRecord->osbuiltin_swaptime, s);

        // Any GPU rendertime queries submitted whose results we shall collect?
        if ((infoType != 7) && (windowRecord->gpuRenderTimeQuery)) {
            // Yes: Poll if query result is available, otherwise no-op for this invocation:
            gpuTimeElapsed = 0;
            glGetQueryObjectuiv(windowRecord->gpuRenderTimeQuery, GL_QUERY_RESULT_AVAILABLE, &gpuTimeElapsed);
            if (gpuTimeElapsed > 0) {
                // Result available: Get it!
                glGetQueryObjectuiv(windowRecord->gpuRenderTimeQuery, GL_QUERY_RESULT, &gpuTimeElapsed);

                // Destroy query object:
                glDeleteQueries(1, &windowRecord->gpuRenderTimeQuery);
                windowRecord->gpuRenderTimeQuery = 0;

                // Make sure that any successful query with a result at least records 1 Nanosecond of
                // used time. Otherwise a context with no gpu activity and zero used time would cause
                // a zero result, which also means "no result available" and causes user-script hang:
                if (gpuTimeElapsed == 0)
                    gpuTimeElapsed = 1;

                // Convert result in Nanoseconds back to seconds, and assign it:
                windowRecord->gpuRenderTime = (double) gpuTimeElapsed / (double) 1e9;
            }
        }

        // Result from last GPU rendertime query as triggered by infoType 5: Zero if undefined.
        PsychSetStructArrayDoubleElement("GPULastFrameRenderTime", 0, windowRecord->gpuRenderTime, s);

        // Try to determine system time of last VBL on display, independent of any
        // flips / bufferswaps.
        lastvbl = -1;
        postflip_vblcount = 0;

        // On supported systems, we can query the OS for the system time of last VBL, so we can
        // use the most recent VBL timestamp as baseline for timing calculations,
        // instead of one far in the past.
        if (onscreen) { lastvbl = PsychOSGetVBLTimeAndCount(windowRecord, &postflip_vblcount); }

        // If we couldn't determine this information we just set lastvbl to the last known
        // vbl timestamp of last flip -- better than nothing...
        if (lastvbl < 0) lastvbl = windowRecord->time_at_last_vbl;
        PsychSetStructArrayDoubleElement("LastVBLTime", 0, lastvbl, s);
        PsychSetStructArrayDoubleElement("VBLCount", 0, (double) (psych_int64) postflip_vblcount, s);

        // Misc. window parameters:
        PsychSetStructArrayDoubleElement("StereoMode", 0, windowRecord->stereomode, s);
        PsychSetStructArrayDoubleElement("ImagingMode", 0, windowRecord->imagingMode, s);
        // FIXME: Caution: specialflags is 64 bits, but double can only return about 53 low-bits correctly. 
        PsychSetStructArrayDoubleElement("SpecialFlags", 0, (double) windowRecord->specialflags, s);
        PsychSetStructArrayDoubleElement("IsFullscreen", 0, (windowRecord->specialflags & kPsychIsFullscreenWindow) ? 1 : 0, s);
        PsychSetStructArrayDoubleElement("MultiSampling", 0, windowRecord->multiSample, s);
        PsychSetStructArrayDoubleElement("MissedDeadlines", 0, windowRecord->nr_missed_deadlines, s);
        PsychSetStructArrayDoubleElement("FlipCount", 0, windowRecord->flipCount, s);
        PsychSetStructArrayDoubleElement("StereoDrawBuffer", 0, windowRecord->stereodrawbuffer, s);
        PsychSetStructArrayDoubleElement("GuesstimatedMemoryUsageMB", 0, (double) windowRecord->surfaceSizeBytes / 1024 / 1024, s);
        PsychSetStructArrayDoubleElement("BitsPerColorComponent", 0, (double) windowRecord->bpc, s);

        // Return VBL startline:
        PsychSetStructArrayDoubleElement("VBLStartline", 0, (double) windowRecord->VBL_Startline, s);

        // And VBL endline:
        PsychSetStructArrayDoubleElement("VBLEndline", 0, windowRecord->VBL_Endline, s);

        // Video refresh interval duration from beamposition method:
        PsychSetStructArrayDoubleElement("VideoRefreshFromBeamposition", 0, windowRecord->ifi_beamestimate, s);

        // Swap group assignment and swap barrier assignment, if any:
        PsychSetStructArrayDoubleElement("SwapGroup", 0, windowRecord->swapGroup, s);
        PsychSetStructArrayDoubleElement("SwapBarrier", 0, windowRecord->swapBarrier, s);

        // Windowing system low-level onscreen window handle or equivalent info:
        #if (PSYCH_SYSTEM == PSYCH_LINUX) && !defined(PTB_USE_WAYLAND)
            // Linux/X11: The X-Window handle 'Window':
            PsychSetStructArrayUnsignedInt64Element("SysWindowHandle", 0, (psych_uint64) (size_t) windowRecord->targetSpecific.xwindowHandle, s);
        #else
            PsychSetStructArrayUnsignedInt64Element("SysWindowHandle", 0, (psych_uint64) (size_t) windowRecord->targetSpecific.windowHandle, s);
        #endif

        // Windowing system low-level onscreen window related handle used for graphics/display api interop in some way: macOS use only atm.
        PsychSetStructArrayUnsignedInt64Element("SysWindowInteropHandle", 0, (psych_uint64) (size_t) windowRecord->targetSpecific.deviceContext, s);

        // Scaling factor for input coordinate transformation functions like RemapMouse.m:
        PsychSetStructArrayDoubleElement("ExternalMouseMultFactor", 0, windowRecord->externalMouseMultFactor, s);

        // Effectively selected VRR mode - ergo excluding 1 for "automatic", as that one would have mapped to a > 1 mode already:
        PsychSetStructArrayDoubleElement("VRRMode", 0, windowRecord->vrrMode, s);

        // Current assumption about VRR timing style:
        PsychSetStructArrayDoubleElement("VRRStyleHint", 0, windowRecord->vrrStyleHint, s);

        // Current assumption about VRR system latency:
        PsychSetStructArrayDoubleElement("VRRLatencyCompensation", 0, windowRecord->vrrLatencyCompensation, s);

        // Which basic GPU architecture is this?
        PsychSetStructArrayStringElement("GPUCoreId", 0, windowRecord->gpuCoreId, s);

        // FBO's supported, and how deep?
        if (windowRecord->gfxcaps & kPsychGfxCapFBO) {
            if (windowRecord->gfxcaps & kPsychGfxCapFPFBO32) {
                PsychSetStructArrayDoubleElement("GLSupportsFBOUpToBpc", 0, 32, s);
            } else
            if (windowRecord->gfxcaps & kPsychGfxCapFPFBO16) {
                PsychSetStructArrayDoubleElement("GLSupportsFBOUpToBpc", 0, 16, s);
            } else PsychSetStructArrayDoubleElement("GLSupportsFBOUpToBpc", 0, 8, s);
        }
        else {
            PsychSetStructArrayDoubleElement("GLSupportsFBOUpToBpc", 0, 0, s);
        }

        // How deep is alpha blending supported?
        if (windowRecord->gfxcaps & kPsychGfxCapFPBlend32) {
            PsychSetStructArrayDoubleElement("GLSupportsBlendingUpToBpc", 0, 32, s);
        } else if (windowRecord->gfxcaps & kPsychGfxCapFPBlend16) {
            PsychSetStructArrayDoubleElement("GLSupportsBlendingUpToBpc", 0, 16, s);
        } else PsychSetStructArrayDoubleElement("GLSupportsBlendingUpToBpc", 0, 8, s);

        // How deep is texture mapping supported?
        if (windowRecord->gfxcaps & kPsychGfxCapFPTex32) {
            PsychSetStructArrayDoubleElement("GLSupportsTexturesUpToBpc", 0, 32, s);
        } else if (windowRecord->gfxcaps & kPsychGfxCapFPTex16) {
            PsychSetStructArrayDoubleElement("GLSupportsTexturesUpToBpc", 0, 16, s);
        } else PsychSetStructArrayDoubleElement("GLSupportsTexturesUpToBpc", 0, 8, s);

        // How deep is texture filtering supported?
        if (windowRecord->gfxcaps & kPsychGfxCapFPFilter32) {
            PsychSetStructArrayDoubleElement("GLSupportsFilteringUpToBpc", 0, 32, s);
        } else if (windowRecord->gfxcaps & kPsychGfxCapFPFilter16) {
            PsychSetStructArrayDoubleElement("GLSupportsFilteringUpToBpc", 0, 16, s);
        } else PsychSetStructArrayDoubleElement("GLSupportsFilteringUpToBpc", 0, 8, s);

        if (windowRecord->gfxcaps & kPsychGfxCapVCGood) {
            PsychSetStructArrayDoubleElement("GLSupportsPrecisionColors", 0, 1, s);
        } else PsychSetStructArrayDoubleElement("GLSupportsPrecisionColors", 0, 0, s);

        if (windowRecord->gfxcaps & kPsychGfxCapFP32Shading) {
            PsychSetStructArrayDoubleElement("GLSupportsFP32Shading", 0, 1, s);
        } else PsychSetStructArrayDoubleElement("GLSupportsFP32Shading", 0, 0, s);

        // Try to get and return vendor specific gpuMaintype + gpuMinorType:
        // On AMD gpuMinorType is the DCE display engine revision, on NVidia the chip family name:
        gpuMaintype = 0;
        if (!PsychGetGPUSpecs(windowRecord->screenNumber, &gpuMaintype, &gpuMinorType, NULL, NULL)) {
            // Query failed or unsupported:
            PsychSetStructArrayDoubleElement("GPUMinorType", 0, -1, s);
        }
        else {
            PsychSetStructArrayDoubleElement("GPUMinorType", 0, (double) gpuMinorType, s);
        }

        switch (gpuMaintype) {
            case kPsychGeForce:
                PsychSetStructArrayStringElement("DisplayCoreId", 0, "NVidia", s);
                break;
            case kPsychRadeon:
                PsychSetStructArrayStringElement("DisplayCoreId", 0, "AMD", s);
                break;
            case kPsychIntelIGP:
                PsychSetStructArrayStringElement("DisplayCoreId", 0, "Intel", s);
                break;
            default:
                PsychSetStructArrayStringElement("DisplayCoreId", 0, windowRecord->gpuCoreId, s);
                break;
        }

        if (infoType != 7) {
            // Renderer information: This comes last, and would fail if async flips
            // are active, because it needs PsychSetDrawingTarget, which in turn needs async
            // flips to be inactive, unless imaging pipeline is fully enabled:
            PsychSetStructArrayStringElement("GLVendor", 0, (char*) glGetString(GL_VENDOR), s);
            PsychSetStructArrayStringElement("GLRenderer", 0, (char*) glGetString(GL_RENDERER), s);
            PsychSetStructArrayStringElement("GLVersion", 0, (char*) glGetString(GL_VERSION), s);

            // Try to get and return the OpenGL device UUID. Useful for uniquely identifying a
            // physical gpu in the system. Note the UUID computation is not standardized, so each
            // OpenGL driver/vendor may use a different method, ergo UUID are only comparable within
            // gpu's of a specific gpu vendor:
            if (glewIsSupported("GL_EXT_memory_object")) {
                GLint numUUIDS = 0;
                PsychGenericScriptType *out_uuid;
                psych_uint8 *devUUID = NULL;

                // AMD: Mesa radeonsi OpenGL PCI:domain:bus:device:function == Mesa radv. 32-bit per field.
                //      amdvlk bus:device:function:0
                // => Can convert to amdvlk / amdgpu-pro style.
                // NVidia: Identical hash between OpenGL and Vulkan.
                // Intel and others: Unsupported.
                glGetIntegerv(GL_NUM_DEVICE_UUIDS_EXT, &numUUIDS);
                if (numUUIDS > 0) {
                    PsychAllocateNativeUnsignedByteMat(1, GL_UUID_SIZE_EXT, 1, (psych_uint8**) &devUUID, &out_uuid);
                    glGetUnsignedBytei_vEXT(GL_DEVICE_UUID_EXT, 0, devUUID);
                    PsychSetStructArrayNativeElement("GLDeviceUUID", 0, out_uuid, s);
                }
            }
        }
    }

    // Done.
    return(PsychError_none);
}