comparison src/video/quartz/SDL_QuartzVideo.m @ 1340:58b114ef50e7

Faster fades when changing to/from/between fullscreen modes on Mac OS X. Also, it doesn't show the desktop between modes anymore. Fixes Bugzilla #100. --ryan.
author Ryan C. Gordon <icculus@icculus.org>
date Tue, 07 Feb 2006 11:18:21 +0000
parents 092722dbc766
children 376665398b25
comparison
equal deleted inserted replaced
1339:62802d9d7c87 1340:58b114ef50e7
65 /* Initialization, Query, Setup, and Redrawing functions */ 65 /* Initialization, Query, Setup, and Redrawing functions */
66 static int QZ_VideoInit (_THIS, SDL_PixelFormat *video_format); 66 static int QZ_VideoInit (_THIS, SDL_PixelFormat *video_format);
67 67
68 static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, 68 static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format,
69 Uint32 flags); 69 Uint32 flags);
70 static void QZ_UnsetVideoMode (_THIS); 70 static void QZ_UnsetVideoMode (_THIS, BOOL to_desktop);
71 71
72 static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, 72 static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current,
73 int width, int height, int bpp, 73 int width, int height, int bpp,
74 Uint32 flags); 74 Uint32 flags);
75 static int QZ_ToggleFullScreen (_THIS, int on); 75 static int QZ_ToggleFullScreen (_THIS, int on);
343 } 343 }
344 } 344 }
345 return SDL_FALSE; 345 return SDL_FALSE;
346 } 346 }
347 347
348 /* 348 static void QZ_UnsetVideoMode (_THIS, BOOL to_desktop) {
349 Gamma functions to try to hide the flash from a rez switch
350 Fade the display from normal to black
351 Save gamma tables for fade back to normal
352 */
353 static UInt32 QZ_FadeGammaOut (_THIS, SDL_QuartzGammaTable *table) {
354
355 CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE],
356 greenTable[QZ_GAMMA_TABLE_SIZE],
357 blueTable[QZ_GAMMA_TABLE_SIZE];
358
359 float percent;
360 int j;
361 int actual;
362
363 if ( (CGDisplayNoErr != CGGetDisplayTransferByTable
364 (display_id, QZ_GAMMA_TABLE_SIZE,
365 table->red, table->green, table->blue, &actual)) ||
366 actual != QZ_GAMMA_TABLE_SIZE) {
367
368 return 1;
369 }
370
371 memcpy (redTable, table->red, sizeof(redTable));
372 memcpy (greenTable, table->green, sizeof(greenTable));
373 memcpy (blueTable, table->blue, sizeof(greenTable));
374
375 for (percent = 1.0; percent >= 0.0; percent -= 0.01) {
376
377 for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
378
379 redTable[j] = redTable[j] * percent;
380 greenTable[j] = greenTable[j] * percent;
381 blueTable[j] = blueTable[j] * percent;
382 }
383
384 if (CGDisplayNoErr != CGSetDisplayTransferByTable
385 (display_id, QZ_GAMMA_TABLE_SIZE,
386 redTable, greenTable, blueTable)) {
387
388 CGDisplayRestoreColorSyncSettings();
389 return 1;
390 }
391
392 SDL_Delay (10);
393 }
394
395 return 0;
396 }
397
398 /*
399 Fade the display from black to normal
400 Restore previously saved gamma values
401 */
402 static UInt32 QZ_FadeGammaIn (_THIS, SDL_QuartzGammaTable *table) {
403
404 CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE],
405 greenTable[QZ_GAMMA_TABLE_SIZE],
406 blueTable[QZ_GAMMA_TABLE_SIZE];
407
408 float percent;
409 int j;
410
411 memset (redTable, 0, sizeof(redTable));
412 memset (greenTable, 0, sizeof(greenTable));
413 memset (blueTable, 0, sizeof(greenTable));
414
415 for (percent = 0.0; percent <= 1.0; percent += 0.01) {
416
417 for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
418
419 redTable[j] = table->red[j] * percent;
420 greenTable[j] = table->green[j] * percent;
421 blueTable[j] = table->blue[j] * percent;
422 }
423
424 if (CGDisplayNoErr != CGSetDisplayTransferByTable
425 (display_id, QZ_GAMMA_TABLE_SIZE,
426 redTable, greenTable, blueTable)) {
427
428 CGDisplayRestoreColorSyncSettings();
429 return 1;
430 }
431
432 SDL_Delay (10);
433 }
434
435 return 0;
436 }
437
438 static void QZ_UnsetVideoMode (_THIS) {
439 349
440 /* Reset values that may change between switches */ 350 /* Reset values that may change between switches */
441 this->info.blit_fill = 0; 351 this->info.blit_fill = 0;
442 this->FillHWRect = NULL; 352 this->FillHWRect = NULL;
443 this->UpdateRects = NULL; 353 this->UpdateRects = NULL;
445 this->UnlockHWSurface = NULL; 355 this->UnlockHWSurface = NULL;
446 356
447 /* Release fullscreen resources */ 357 /* Release fullscreen resources */
448 if ( mode_flags & SDL_FULLSCREEN ) { 358 if ( mode_flags & SDL_FULLSCREEN ) {
449 359
450 SDL_QuartzGammaTable gamma_table;
451 int gamma_error;
452 NSRect screen_rect; 360 NSRect screen_rect;
453 361
454 gamma_error = QZ_FadeGammaOut (this, &gamma_table);
455
456 /* Release double buffer stuff */ 362 /* Release double buffer stuff */
457 if ( mode_flags & SDL_DOUBLEBUF) { 363 if ( mode_flags & SDL_DOUBLEBUF) {
458 quit_thread = YES; 364 quit_thread = YES;
459 SDL_SemPost (sem1); 365 SDL_SemPost (sem1);
460 SDL_WaitThread (thread, NULL); 366 SDL_WaitThread (thread, NULL);
470 if ( mode_flags & SDL_OPENGL ) { 376 if ( mode_flags & SDL_OPENGL ) {
471 377
472 QZ_TearDownOpenGL (this); 378 QZ_TearDownOpenGL (this);
473 CGLSetFullScreen (NULL); 379 CGLSetFullScreen (NULL);
474 } 380 }
475 381 if (to_desktop) {
476 /* Restore original screen resolution/bpp */ 382 /* Restore original screen resolution/bpp */
477 CGDisplaySwitchToMode (display_id, save_mode); 383 CGDisplaySwitchToMode (display_id, save_mode);
478 CGReleaseAllDisplays (); 384 CGReleaseAllDisplays ();
479 ShowMenuBar (); 385 ShowMenuBar ();
480 /* 386 /*
481 Reset the main screen's rectangle 387 Reset the main screen's rectangle
482 See comment in QZ_SetVideoFullscreen for why we do this 388 See comment in QZ_SetVideoFullscreen for why we do this
483 */ 389 */
484 screen_rect = NSMakeRect(0,0,device_width,device_height); 390 screen_rect = NSMakeRect(0,0,device_width,device_height);
485 [ [ NSScreen mainScreen ] setFrame:screen_rect ]; 391 [ [ NSScreen mainScreen ] setFrame:screen_rect ];
486 392 }
487 if (! gamma_error)
488 QZ_FadeGammaIn (this, &gamma_table);
489 } 393 }
490 /* Release window mode resources */ 394 /* Release window mode resources */
491 else { 395 else {
492 396
493 [ qz_window close ]; 397 [ qz_window close ];
505 } 409 }
506 410
507 static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int width, 411 static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int width,
508 int height, int bpp, Uint32 flags) { 412 int height, int bpp, Uint32 flags) {
509 boolean_t exact_match = 0; 413 boolean_t exact_match = 0;
510 int gamma_error;
511 SDL_QuartzGammaTable gamma_table;
512 NSRect screen_rect; 414 NSRect screen_rect;
513 CGError error; 415 CGError error;
416 CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken;
417
418 /* Fade to black to hide resolution-switching flicker (and garbage
419 that is displayed by a destroyed OpenGL context, if applicable) */
420 if ( CGAcquireDisplayFadeReservation (5, &fade_token) == kCGErrorSuccess ) {
421 CGDisplayFade (fade_token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE);
422 }
514 423
515 /* Destroy any previous mode */ 424 /* Destroy any previous mode */
516 if (video_set == SDL_TRUE) 425 if (video_set == SDL_TRUE)
517 QZ_UnsetVideoMode (this); 426 QZ_UnsetVideoMode (this, FALSE);
518 427
519 /* See if requested mode exists */ 428 /* See if requested mode exists */
520 mode = CGDisplayBestModeForParameters (display_id, bpp, width, 429 mode = CGDisplayBestModeForParameters (display_id, bpp, width,
521 height, &exact_match); 430 height, &exact_match);
522 431
523 /* Require an exact match to the requested mode */ 432 /* Require an exact match to the requested mode */
524 if ( ! exact_match ) { 433 if ( ! exact_match ) {
525 SDL_SetError ("Failed to find display resolution: %dx%dx%d", width, height, bpp); 434 SDL_SetError ("Failed to find display resolution: %dx%dx%d", width, height, bpp);
526 goto ERR_NO_MATCH; 435 goto ERR_NO_MATCH;
527 } 436 }
528
529 /* Fade display to zero gamma */
530 gamma_error = QZ_FadeGammaOut (this, &gamma_table);
531 437
532 /* Put up the blanking window (a window above all other windows) */ 438 /* Put up the blanking window (a window above all other windows) */
533 if (getenv ("SDL_SINGLEDISPLAY")) 439 if (getenv ("SDL_SINGLEDISPLAY"))
534 error = CGDisplayCapture (display_id); 440 error = CGDisplayCapture (display_id);
535 else 441 else
627 } 533 }
628 534
629 /* If we don't hide menu bar, it will get events and interrupt the program */ 535 /* If we don't hide menu bar, it will get events and interrupt the program */
630 HideMenuBar (); 536 HideMenuBar ();
631 537
632 /* Fade the display to original gamma */ 538 /* Fade in again (asynchronously) */
633 if (! gamma_error ) 539 if ( fade_token != kCGDisplayFadeReservationInvalidToken ) {
634 QZ_FadeGammaIn (this, &gamma_table); 540 CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
541 CGReleaseDisplayFadeReservation(fade_token);
542 }
635 543
636 /* 544 /*
637 There is a bug in Cocoa where NSScreen doesn't synchronize 545 There is a bug in Cocoa where NSScreen doesn't synchronize
638 with CGDirectDisplay, so the main screen's frame is wrong. 546 with CGDirectDisplay, so the main screen's frame is wrong.
639 As a result, coordinate translation produces incorrect results. 547 As a result, coordinate translation produces incorrect results.
653 561
654 /* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */ 562 /* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */
655 ERR_NO_GL: 563 ERR_NO_GL:
656 ERR_DOUBLEBUF: CGDisplaySwitchToMode (display_id, save_mode); 564 ERR_DOUBLEBUF: CGDisplaySwitchToMode (display_id, save_mode);
657 ERR_NO_SWITCH: CGReleaseAllDisplays (); 565 ERR_NO_SWITCH: CGReleaseAllDisplays ();
658 ERR_NO_CAPTURE: if (!gamma_error) { QZ_FadeGammaIn (this, &gamma_table); } 566 ERR_NO_CAPTURE:
659 ERR_NO_MATCH: return NULL; 567 ERR_NO_MATCH: if ( fade_token != kCGDisplayFadeReservationInvalidToken ) {
568 CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
569 CGReleaseDisplayFadeReservation (fade_token);
570 }
571 return NULL;
660 } 572 }
661 573
662 static SDL_Surface* QZ_SetVideoWindowed (_THIS, SDL_Surface *current, int width, 574 static SDL_Surface* QZ_SetVideoWindowed (_THIS, SDL_Surface *current, int width,
663 int height, int *bpp, Uint32 flags) { 575 int height, int *bpp, Uint32 flags) {
664 unsigned int style; 576 unsigned int style;
665 NSRect contentRect; 577 NSRect contentRect;
666 BOOL isCustom = NO; 578 BOOL isCustom = NO;
667 int center_window = 1; 579 int center_window = 1;
668 int origin_x, origin_y; 580 int origin_x, origin_y;
581 CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken;
669 582
670 current->flags = 0; 583 current->flags = 0;
671 current->w = width; 584 current->w = width;
672 current->h = height; 585 current->h = height;
673 586
678 - If it is fullscreen 591 - If it is fullscreen
679 - If it has different noframe or resizable attribute 592 - If it has different noframe or resizable attribute
680 - If it is OpenGL (since gl attributes could be different) 593 - If it is OpenGL (since gl attributes could be different)
681 - If new mode is OpenGL, but previous mode wasn't 594 - If new mode is OpenGL, but previous mode wasn't
682 */ 595 */
683 if (video_set == SDL_TRUE) 596 if (video_set == SDL_TRUE) {
684 if ( (mode_flags & SDL_FULLSCREEN) || 597 if (mode_flags & SDL_FULLSCREEN) {
685 ((mode_flags ^ flags) & (SDL_NOFRAME|SDL_RESIZABLE)) || 598 /* Fade to black to hide resolution-switching flicker (and garbage
686 (mode_flags & SDL_OPENGL) || 599 that is displayed by a destroyed OpenGL context, if applicable) */
687 (flags & SDL_OPENGL) ) 600 if (CGAcquireDisplayFadeReservation (5, &fade_token) == kCGErrorSuccess) {
688 QZ_UnsetVideoMode (this); 601 CGDisplayFade (fade_token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE);
602 }
603 QZ_UnsetVideoMode (this, TRUE);
604 }
605 else if ( ((mode_flags ^ flags) & (SDL_NOFRAME|SDL_RESIZABLE)) ||
606 (mode_flags & SDL_OPENGL) ||
607 (flags & SDL_OPENGL) ) {
608 QZ_UnsetVideoMode (this, TRUE);
609 }
610 }
689 611
690 /* Check for user-specified window and view */ 612 /* Check for user-specified window and view */
691 { 613 {
692 char *windowPtrString = getenv ("SDL_NSWindowPointer"); 614 char *windowPtrString = getenv ("SDL_NSWindowPointer");
693 char *viewPtrString = getenv ("SDL_NSQuickDrawViewPointer"); 615 char *viewPtrString = getenv ("SDL_NSQuickDrawViewPointer");
750 backing:NSBackingStoreBuffered 672 backing:NSBackingStoreBuffered
751 defer:NO ]; 673 defer:NO ];
752 674
753 if (qz_window == nil) { 675 if (qz_window == nil) {
754 SDL_SetError ("Could not create the Cocoa window"); 676 SDL_SetError ("Could not create the Cocoa window");
677 if (fade_token != kCGDisplayFadeReservationInvalidToken) {
678 CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
679 CGReleaseDisplayFadeReservation (fade_token);
680 }
755 return NULL; 681 return NULL;
756 } 682 }
757 683
758 //[ qz_window setReleasedWhenClosed:YES ]; 684 //[ qz_window setReleasedWhenClosed:YES ];
759 QZ_SetCaption(this, this->wm_title, this->wm_icon); 685 QZ_SetCaption(this, this->wm_title, this->wm_icon);
777 703
778 /* For OpenGL, we bind the context to a subview */ 704 /* For OpenGL, we bind the context to a subview */
779 if ( flags & SDL_OPENGL ) { 705 if ( flags & SDL_OPENGL ) {
780 706
781 if ( ! QZ_SetupOpenGL (this, *bpp, flags) ) { 707 if ( ! QZ_SetupOpenGL (this, *bpp, flags) ) {
708 if (fade_token != kCGDisplayFadeReservationInvalidToken) {
709 CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
710 CGReleaseDisplayFadeReservation (fade_token);
711 }
782 return NULL; 712 return NULL;
783 } 713 }
784 714
785 window_view = [ [ NSView alloc ] initWithFrame:contentRect ]; 715 window_view = [ [ NSView alloc ] initWithFrame:contentRect ];
786 [ window_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ]; 716 [ window_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
835 this->UnlockHWSurface = QZ_UnlockWindow; 765 this->UnlockHWSurface = QZ_UnlockWindow;
836 } 766 }
837 767
838 /* Save flags to ensure correct teardown */ 768 /* Save flags to ensure correct teardown */
839 mode_flags = current->flags; 769 mode_flags = current->flags;
770
771 /* Fade in again (asynchronously) if we came from a fullscreen mode and faded to black */
772 if (fade_token != kCGDisplayFadeReservationInvalidToken) {
773 CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
774 CGReleaseDisplayFadeReservation (fade_token);
775 }
840 776
841 return current; 777 return current;
842 } 778 }
843 779
844 static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width, 780 static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width,
1493 } 1429 }
1494 } 1430 }
1495 1431
1496 static void QZ_VideoQuit (_THIS) { 1432 static void QZ_VideoQuit (_THIS) {
1497 1433
1434 CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken;
1435
1498 /* Restore gamma settings */ 1436 /* Restore gamma settings */
1499 CGDisplayRestoreColorSyncSettings (); 1437 CGDisplayRestoreColorSyncSettings ();
1500 1438
1501 /* Ensure the cursor will be visible and working when we quit */ 1439 /* Ensure the cursor will be visible and working when we quit */
1502 CGDisplayShowCursor (display_id); 1440 CGDisplayShowCursor (display_id);
1503 CGAssociateMouseAndMouseCursorPosition (1); 1441 CGAssociateMouseAndMouseCursorPosition (1);
1504 1442
1505 QZ_UnsetVideoMode (this); 1443 if (mode_flags & SDL_FULLSCREEN) {
1444 /* Fade to black to hide resolution-switching flicker (and garbage
1445 that is displayed by a destroyed OpenGL context, if applicable) */
1446 if (CGAcquireDisplayFadeReservation (5, &fade_token) == kCGErrorSuccess) {
1447 CGDisplayFade (fade_token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE);
1448 }
1449 QZ_UnsetVideoMode (this, TRUE);
1450 if (fade_token != kCGDisplayFadeReservationInvalidToken) {
1451 CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
1452 CGReleaseDisplayFadeReservation (fade_token);
1453 }
1454 }
1455 else
1456 QZ_UnsetVideoMode (this, TRUE);
1457
1506 CGPaletteRelease (palette); 1458 CGPaletteRelease (palette);
1507 1459
1508 if (opengl_library) { 1460 if (opengl_library) {
1509 SDL_UnloadObject(opengl_library); 1461 SDL_UnloadObject(opengl_library);
1510 opengl_library = NULL; 1462 opengl_library = NULL;