Mercurial > sdl-ios-xcode
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; |