src/video/quartz/SDL_QuartzVideo.m
branchSDL-1.2
changeset 5569 d81e8404bd7f
parent 5568 abe7d0b3539b
child 5574 7b7ad16f9704
equal deleted inserted replaced
5568:abe7d0b3539b 5569:d81e8404bd7f
    82                                          Uint32 flags);
    82                                          Uint32 flags);
    83 static int          QZ_ToggleFullScreen (_THIS, int on);
    83 static int          QZ_ToggleFullScreen (_THIS, int on);
    84 static int          QZ_SetColors        (_THIS, int first_color,
    84 static int          QZ_SetColors        (_THIS, int first_color,
    85                                          int num_colors, SDL_Color *colors);
    85                                          int num_colors, SDL_Color *colors);
    86 
    86 
    87 static int          QZ_LockDoubleBuffer   (_THIS, SDL_Surface *surface);
       
    88 static void         QZ_UnlockDoubleBuffer (_THIS, SDL_Surface *surface);
       
    89 static int          QZ_ThreadFlip         (_THIS);
       
    90 static int          QZ_FlipDoubleBuffer   (_THIS, SDL_Surface *surface);
       
    91 static void         QZ_DoubleBufferUpdate (_THIS, int num_rects, SDL_Rect *rects);
       
    92 
       
    93 static void         QZ_DirectUpdate     (_THIS, int num_rects, SDL_Rect *rects);
       
    94 static void         QZ_UpdateRects      (_THIS, int num_rects, SDL_Rect *rects);
    87 static void         QZ_UpdateRects      (_THIS, int num_rects, SDL_Rect *rects);
    95 static void         QZ_VideoQuit        (_THIS);
    88 static void         QZ_VideoQuit        (_THIS);
    96 
    89 
    97 /* Hardware surface functions (for fullscreen mode only) */
       
    98 #if 0 /* Not used (apparently, it's really slow) */
       
    99 static int  QZ_FillHWRect (_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color);
       
   100 #endif
       
   101 static int  QZ_LockHWSurface(_THIS, SDL_Surface *surface);
    90 static int  QZ_LockHWSurface(_THIS, SDL_Surface *surface);
   102 static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface);
    91 static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface);
   103 static int QZ_AllocHWSurface(_THIS, SDL_Surface *surface);
    92 static int QZ_AllocHWSurface(_THIS, SDL_Surface *surface);
   104 static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface);
    93 static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface);
   105 /* static int  QZ_FlipHWSurface (_THIS, SDL_Surface *surface); */
       
   106 
    94 
   107 /* Bootstrap binding, enables entry point into the driver */
    95 /* Bootstrap binding, enables entry point into the driver */
   108 VideoBootStrap QZ_bootstrap = {
    96 VideoBootStrap QZ_bootstrap = {
   109     "Quartz", "Mac OS X CoreGraphics", QZ_Available, QZ_CreateDevice
    97     "Quartz", "Mac OS X CoreGraphics", QZ_Available, QZ_CreateDevice
   110 };
    98 };
   138     device->ListModes        = QZ_ListModes;
   126     device->ListModes        = QZ_ListModes;
   139     device->SetVideoMode     = QZ_SetVideoMode;
   127     device->SetVideoMode     = QZ_SetVideoMode;
   140     device->ToggleFullScreen = QZ_ToggleFullScreen;
   128     device->ToggleFullScreen = QZ_ToggleFullScreen;
   141     device->UpdateMouse      = QZ_UpdateMouse;
   129     device->UpdateMouse      = QZ_UpdateMouse;
   142     device->SetColors        = QZ_SetColors;
   130     device->SetColors        = QZ_SetColors;
   143     /* device->UpdateRects      = QZ_UpdateRects; this is determined by SetVideoMode() */
   131     device->UpdateRects      = QZ_UpdateRects;
   144     device->VideoQuit        = QZ_VideoQuit;
   132     device->VideoQuit        = QZ_VideoQuit;
   145 
   133 
   146     device->LockHWSurface   = QZ_LockHWSurface;
   134     device->LockHWSurface   = QZ_LockHWSurface;
   147     device->UnlockHWSurface = QZ_UnlockHWSurface;
   135     device->UnlockHWSurface = QZ_UnlockHWSurface;
   148     device->AllocHWSurface   = QZ_AllocHWSurface;
   136     device->AllocHWSurface   = QZ_AllocHWSurface;
   149     device->FreeHWSurface   = QZ_FreeHWSurface;
   137     device->FreeHWSurface   = QZ_FreeHWSurface;
   150     /* device->FlipHWSurface   = QZ_FlipHWSurface */;
       
   151 
   138 
   152     device->SetGamma     = QZ_SetGamma;
   139     device->SetGamma     = QZ_SetGamma;
   153     device->GetGamma     = QZ_GetGamma;
   140     device->GetGamma     = QZ_GetGamma;
   154     device->SetGammaRamp = QZ_SetGammaRamp;
   141     device->SetGammaRamp = QZ_SetGammaRamp;
   155     device->GetGammaRamp = QZ_GetGammaRamp;
   142     device->GetGammaRamp = QZ_GetGammaRamp;
   396 
   383 
   397 static void QZ_UnsetVideoMode (_THIS, BOOL to_desktop)
   384 static void QZ_UnsetVideoMode (_THIS, BOOL to_desktop)
   398 {
   385 {
   399     /* Reset values that may change between switches */
   386     /* Reset values that may change between switches */
   400     this->info.blit_fill  = 0;
   387     this->info.blit_fill  = 0;
   401     this->FillHWRect      = NULL;
   388 
   402     this->UpdateRects     = NULL;
       
   403     this->LockHWSurface   = NULL;
       
   404     this->UnlockHWSurface = NULL;
       
   405     
       
   406     if (cg_context) {
   389     if (cg_context) {
   407         CGContextFlush (cg_context);
   390         CGContextFlush (cg_context);
   408         CGContextRelease (cg_context);
   391         CGContextRelease (cg_context);
   409         cg_context = nil;
   392         cg_context = nil;
   410     }
   393     }
   411     
   394     
   412     /* Release fullscreen resources */
   395     /* Release fullscreen resources */
   413     if ( mode_flags & SDL_FULLSCREEN ) {
   396     if ( mode_flags & SDL_FULLSCREEN ) {
   414 
   397 
   415         NSRect screen_rect;
   398         NSRect screen_rect;
   416         
   399 
   417         /*  Release double buffer stuff */
       
   418         if ( mode_flags & SDL_DOUBLEBUF) {
       
   419             quit_thread = YES;
       
   420             SDL_SemPost (sem1);
       
   421             SDL_WaitThread (thread, NULL);
       
   422             SDL_DestroySemaphore (sem1);
       
   423             SDL_DestroySemaphore (sem2);
       
   424             SDL_free (sw_buffers[0]);
       
   425         }
       
   426         
       
   427         /* If we still have a valid window, close it. */
   400         /* If we still have a valid window, close it. */
   428         if ( qz_window ) {
   401         if ( qz_window ) {
   429             NSCAssert([ qz_window delegate ] == nil, @"full screen window shouldn't have a delegate"); /* if that should ever change, we'd have to release it here */
   402             NSCAssert([ qz_window delegate ] == nil, @"full screen window shouldn't have a delegate"); /* if that should ever change, we'd have to release it here */
   430             [ qz_window close ]; /* includes release because [qz_window isReleasedWhenClosed] */
   403             [ qz_window close ]; /* includes release because [qz_window isReleasedWhenClosed] */
   431             qz_window = nil;
   404             qz_window = nil;
   477     NSRect screen_rect;
   450     NSRect screen_rect;
   478     CGError error;
   451     CGError error;
   479     NSRect contentRect;
   452     NSRect contentRect;
   480     CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken;
   453     CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken;
   481 
   454 
       
   455     current->flags = SDL_FULLSCREEN;
       
   456     current->w = width;
       
   457     current->h = height;
       
   458 
   482     contentRect = NSMakeRect (0, 0, width, height);
   459     contentRect = NSMakeRect (0, 0, width, height);
   483 
   460 
   484     /* Fade to black to hide resolution-switching flicker (and garbage
   461     /* Fade to black to hide resolution-switching flicker (and garbage
   485        that is displayed by a destroyed OpenGL context, if applicable) */
   462        that is displayed by a destroyed OpenGL context, if applicable) */
   486     if ( CGAcquireDisplayFadeReservation (5, &fade_token) == kCGErrorSuccess ) {
   463     if ( CGAcquireDisplayFadeReservation (5, &fade_token) == kCGErrorSuccess ) {
   522     if ( CGDisplayNoErr != CGDisplaySwitchToMode (display_id, mode) ) {
   499     if ( CGDisplayNoErr != CGDisplaySwitchToMode (display_id, mode) ) {
   523         SDL_SetError ("Failed switching display resolution");
   500         SDL_SetError ("Failed switching display resolution");
   524         goto ERR_NO_SWITCH;
   501         goto ERR_NO_SWITCH;
   525     }
   502     }
   526 
   503 
   527     current->pixels = (Uint32*) CGDisplayBaseAddress (display_id);
       
   528     current->pitch  = CGDisplayBytesPerRow (display_id);
       
   529 
       
   530     current->flags = 0;
       
   531     current->w = width;
       
   532     current->h = height;
       
   533     current->flags |= SDL_FULLSCREEN;
       
   534     current->flags |= SDL_HWSURFACE;
       
   535     current->flags |= SDL_PREALLOC;
       
   536     /* current->hwdata = (void *) CGDisplayGetDrawingContext (display_id); */
       
   537 
       
   538     this->UpdateRects     = QZ_DirectUpdate;
       
   539     this->LockHWSurface   = QZ_LockHWSurface;
       
   540     this->UnlockHWSurface = QZ_UnlockHWSurface;
       
   541 
       
   542     /* Setup double-buffer emulation */
       
   543     if ( flags & SDL_DOUBLEBUF ) {
       
   544         
       
   545         /*
       
   546             Setup a software backing store for reasonable results when
       
   547             double buffering is requested (since a single-buffered hardware
       
   548             surface looks hideous).
       
   549             
       
   550             The actual screen blit occurs in a separate thread to allow 
       
   551             other blitting while waiting on the VBL (and hence results in higher framerates).
       
   552         */
       
   553         this->LockHWSurface = NULL;
       
   554         this->UnlockHWSurface = NULL;
       
   555         this->UpdateRects = NULL;
       
   556         
       
   557         current->flags |= (SDL_HWSURFACE|SDL_DOUBLEBUF);
       
   558         this->UpdateRects = QZ_DoubleBufferUpdate;
       
   559         this->LockHWSurface = QZ_LockDoubleBuffer;
       
   560         this->UnlockHWSurface = QZ_UnlockDoubleBuffer;
       
   561         this->FlipHWSurface = QZ_FlipDoubleBuffer;
       
   562 
       
   563         current->pixels = SDL_malloc (current->pitch * current->h * 2);
       
   564         if (current->pixels == NULL) {
       
   565             SDL_OutOfMemory ();
       
   566             goto ERR_DOUBLEBUF;
       
   567         }
       
   568         
       
   569         sw_buffers[0] = current->pixels;
       
   570         sw_buffers[1] = (Uint8*)current->pixels + current->pitch * current->h;
       
   571         
       
   572         quit_thread = NO;
       
   573         sem1 = SDL_CreateSemaphore (0);
       
   574         sem2 = SDL_CreateSemaphore (1);
       
   575         thread = SDL_CreateThread ((int (*)(void *))QZ_ThreadFlip, this);
       
   576     }
       
   577 
       
   578     if ( CGDisplayCanSetPalette (display_id) )
       
   579         current->flags |= SDL_HWPALETTE;
       
   580 
       
   581     /* Check if we should recreate the window */
   504     /* Check if we should recreate the window */
   582     if (qz_window == nil) {
   505     if (qz_window == nil) {
   583         /* Manually create a window, avoids having a nib file resource */
   506         /* Manually create a window, avoids having a nib file resource */
   584         qz_window = [ [ SDL_QuartzWindow alloc ] 
   507         qz_window = [ [ SDL_QuartzWindow alloc ] 
   585             initWithContentRect:contentRect
   508             initWithContentRect:contentRect
   586                 styleMask:0
   509                 styleMask:NSBorderlessWindowMask
   587                     backing:NSBackingStoreBuffered
   510                     backing:NSBackingStoreBuffered
   588                         defer:NO ];
   511                         defer:NO ];
   589 
   512 
   590         if (qz_window != nil) {
   513         if (qz_window != nil) {
   591             [ qz_window setAcceptsMouseMovedEvents:YES ];
   514             [ qz_window setAcceptsMouseMovedEvents:YES ];
   592             [ qz_window setViewsNeedDisplay:NO ];
   515             [ qz_window setViewsNeedDisplay:NO ];
       
   516             [ qz_window setContentView: [ [ [ SDL_QuartzView alloc ] init ] autorelease ] ];
   593         }
   517         }
   594     }
   518     }
   595     /* We already have a window, just change its size */
   519     /* We already have a window, just change its size */
   596     else {
   520     else {
   597         [ qz_window setContentSize:contentRect.size ];
   521         [ qz_window setContentSize:contentRect.size ];
   603     if (flags & SDL_OPENGL) {
   527     if (flags & SDL_OPENGL) {
   604 
   528 
   605         CGLError err;
   529         CGLError err;
   606         CGLContextObj ctx;
   530         CGLContextObj ctx;
   607 
   531 
       
   532         /* CGLSetFullScreen() will handle this for us. */
       
   533         [ qz_window setLevel:NSNormalWindowLevel ];
       
   534 
   608         if ( ! QZ_SetupOpenGL (this, bpp, flags) ) {
   535         if ( ! QZ_SetupOpenGL (this, bpp, flags) ) {
   609             goto ERR_NO_GL;
   536             goto ERR_NO_GL;
   610         }
   537         }
   611 
   538 
   612         /* Initialize the NSView and add it to our window.  The presence of a valid window and
   539         /* Initialize the NSView and add it to our window.  The presence of a valid window and
   629 
   556 
   630         [ gl_context flushBuffer ];
   557         [ gl_context flushBuffer ];
   631 
   558 
   632         current->flags |= SDL_OPENGL;
   559         current->flags |= SDL_OPENGL;
   633     }
   560     }
       
   561     /* For 2D, we build a CGBitmapContext */
       
   562     else {
       
   563         CGColorSpaceRef cgColorspace;
       
   564 
       
   565         /* Only recreate the view if it doesn't already exist */
       
   566         if (window_view == nil) {
       
   567             window_view = [ [ NSView alloc ] initWithFrame:contentRect ];
       
   568             [ window_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
       
   569             [ [ qz_window contentView ] addSubview:window_view ];
       
   570             [ window_view release ];
       
   571         }
       
   572 
       
   573         cgColorspace = CGColorSpaceCreateDeviceRGB();
       
   574         current->pitch = 4 * current->w;
       
   575         current->pixels = SDL_malloc (current->h * current->pitch);
       
   576         
       
   577         cg_context = CGBitmapContextCreate (current->pixels, current->w, current->h,
       
   578                         8, current->pitch, cgColorspace,
       
   579                         kCGImageAlphaNoneSkipFirst);
       
   580         CGColorSpaceRelease (cgColorspace);
       
   581         
       
   582         current->flags |= SDL_SWSURFACE;
       
   583         current->flags |= SDL_ASYNCBLIT;
       
   584         current->hwdata = (void *) cg_context;
       
   585 
       
   586         /* Force this window to draw above _everything_. */
       
   587         [ qz_window setLevel:CGShieldingWindowLevel() ];
       
   588     }
       
   589 
       
   590     [ qz_window setHasShadow:NO];
       
   591     [ qz_window setOpaque:YES];
       
   592     [ qz_window center ];
       
   593     [ qz_window makeKeyAndOrderFront:nil ];
   634 
   594 
   635     /* If we don't hide menu bar, it will get events and interrupt the program */
   595     /* If we don't hide menu bar, it will get events and interrupt the program */
   636     HideMenuBar ();
   596     HideMenuBar ();
   637 
   597 
   638     /* Fade in again (asynchronously) */
   598     /* Fade in again (asynchronously) */
   819         CGColorSpaceRelease (cgColorspace);
   779         CGColorSpaceRelease (cgColorspace);
   820         
   780         
   821         current->flags |= SDL_SWSURFACE;
   781         current->flags |= SDL_SWSURFACE;
   822         current->flags |= SDL_ASYNCBLIT;
   782         current->flags |= SDL_ASYNCBLIT;
   823         current->hwdata = (void *) cg_context;
   783         current->hwdata = (void *) cg_context;
   824         
       
   825         this->UpdateRects     = QZ_UpdateRects;
       
   826         this->LockHWSurface   = QZ_LockHWSurface;
       
   827         this->UnlockHWSurface = QZ_UnlockHWSurface;
       
   828     }
   784     }
   829 
   785 
   830     /* Save flags to ensure correct teardown */
   786     /* Save flags to ensure correct teardown */
   831     mode_flags = current->flags;
   787     mode_flags = current->flags;
   832 
   788 
   842 static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width,
   798 static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width,
   843                                      int height, int bpp, Uint32 flags)
   799                                      int height, int bpp, Uint32 flags)
   844 {
   800 {
   845     current->flags = 0;
   801     current->flags = 0;
   846     current->pixels = NULL;
   802     current->pixels = NULL;
       
   803 
       
   804     /* Force bpp to 32 */
       
   805     bpp = 32;
   847 
   806 
   848     /* Setup full screen video */
   807     /* Setup full screen video */
   849     if ( flags & SDL_FULLSCREEN ) {
   808     if ( flags & SDL_FULLSCREEN ) {
   850         current = QZ_SetVideoFullScreen (this, current, width, height, bpp, flags );
   809         current = QZ_SetVideoFullScreen (this, current, width, height, bpp, flags );
   851         if (current == NULL)
   810         if (current == NULL)
   852             return NULL;
   811             return NULL;
   853     }
   812     }
   854     /* Setup windowed video */
   813     /* Setup windowed video */
   855     else {
   814     else {
   856         /* Force bpp to 32 */
       
   857         bpp = 32;
       
   858         current = QZ_SetVideoWindowed (this, current, width, height, &bpp, flags);
   815         current = QZ_SetVideoWindowed (this, current, width, height, &bpp, flags);
   859         if (current == NULL)
   816         if (current == NULL)
   860             return NULL;
   817             return NULL;
   861     }
   818     }
   862 
   819 
   877             case 24:
   834             case 24:
   878                 SDL_SetError ("24bpp is not available");
   835                 SDL_SetError ("24bpp is not available");
   879                 return NULL;
   836                 return NULL;
   880             case 32:   /* (8)-8-8-8 ARGB */
   837             case 32:   /* (8)-8-8-8 ARGB */
   881                 amask = 0x00000000;
   838                 amask = 0x00000000;
   882 		if ( flags & SDL_FULLSCREEN )
       
   883 		{
       
   884 			rmask = 0x00FF0000;
       
   885 			gmask = 0x0000FF00;
       
   886 			bmask = 0x000000FF;
       
   887 		}
       
   888 		else
       
   889 		{
       
   890 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   839 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   891 			rmask = 0x0000FF00;
   840                 rmask = 0x0000FF00;
   892 			gmask = 0x00FF0000;
   841                 gmask = 0x00FF0000;
   893 			bmask = 0xFF000000;
   842                 bmask = 0xFF000000;
   894 #else
   843 #else
   895 			rmask = 0x00FF0000;
   844                 rmask = 0x00FF0000;
   896 			gmask = 0x0000FF00;
   845                 gmask = 0x0000FF00;
   897 			bmask = 0x000000FF;
   846                 bmask = 0x000000FF;
   898 #endif
   847 #endif
   899 		}
       
   900                 break;
   848                 break;
   901         }
   849         }
   902 
   850 
   903         if ( ! SDL_ReallocFormat (current, bpp,
   851         if ( ! SDL_ReallocFormat (current, bpp,
   904                                   rmask, gmask, bmask, amask ) ) {
   852                                   rmask, gmask, bmask, amask ) ) {
   938 
   886 
   939     if ( CGDisplayNoErr != CGDisplaySetPalette (display_id, palette) )
   887     if ( CGDisplayNoErr != CGDisplaySetPalette (display_id, palette) )
   940         return 0;
   888         return 0;
   941 
   889 
   942     return 1;
   890     return 1;
   943 }
       
   944 
       
   945 static int QZ_LockDoubleBuffer (_THIS, SDL_Surface *surface)
       
   946 {
       
   947     return 1;
       
   948 }
       
   949 
       
   950 static void QZ_UnlockDoubleBuffer (_THIS, SDL_Surface *surface)
       
   951 {
       
   952 }
       
   953 
       
   954 /* The VBL delay is based on code by Ian R Ollmann's RezLib <iano@cco.caltech.edu> */
       
   955 static AbsoluteTime QZ_SecondsToAbsolute ( double seconds )
       
   956 {
       
   957     union
       
   958     {
       
   959         UInt64 i;
       
   960         Nanoseconds ns;
       
   961     } temp;
       
   962         
       
   963     temp.i = seconds * 1000000000.0;
       
   964     
       
   965     return NanosecondsToAbsolute ( temp.ns );
       
   966 }
       
   967 
       
   968 static int QZ_ThreadFlip (_THIS)
       
   969 {
       
   970     Uint8 *src, *dst;
       
   971     int skip, len, h;
       
   972     
       
   973     /*
       
   974         Give this thread the highest scheduling priority possible,
       
   975         in the hopes that it will immediately run after the VBL delay
       
   976     */
       
   977     {
       
   978         pthread_t current_thread;
       
   979         int policy;
       
   980         struct sched_param param;
       
   981         
       
   982         current_thread = pthread_self ();
       
   983         pthread_getschedparam (current_thread, &policy, &param);
       
   984         policy = SCHED_RR;
       
   985         param.sched_priority = sched_get_priority_max (policy);
       
   986         pthread_setschedparam (current_thread, policy, &param);
       
   987     }
       
   988     
       
   989     while (1) {
       
   990     
       
   991         SDL_SemWait (sem1);
       
   992         if (quit_thread)
       
   993             return 0;
       
   994                 
       
   995         /*
       
   996          * We have to add SDL_VideoSurface->offset here, since we might be a
       
   997          *  smaller surface in the center of the framebuffer (you asked for
       
   998          *  a fullscreen resolution smaller than the hardware could supply
       
   999          *  so SDL is centering it in a bigger resolution)...
       
  1000          */
       
  1001         dst = (Uint8 *)CGDisplayBaseAddress (display_id) + SDL_VideoSurface->offset;
       
  1002         src = current_buffer + SDL_VideoSurface->offset;
       
  1003         len = SDL_VideoSurface->w * SDL_VideoSurface->format->BytesPerPixel;
       
  1004         h = SDL_VideoSurface->h;
       
  1005         skip = SDL_VideoSurface->pitch;
       
  1006     
       
  1007         /* Wait for the VBL to occur (estimated since we don't have a hardware interrupt) */
       
  1008         {
       
  1009             
       
  1010             /* The VBL delay is based on Ian Ollmann's RezLib <iano@cco.caltech.edu> */
       
  1011             double refreshRate;
       
  1012             double linesPerSecond;
       
  1013             double target;
       
  1014             double position;
       
  1015             double adjustment;
       
  1016             AbsoluteTime nextTime;        
       
  1017             CFNumberRef refreshRateCFNumber;
       
  1018             
       
  1019             refreshRateCFNumber = CFDictionaryGetValue (mode, kCGDisplayRefreshRate);
       
  1020             if ( NULL == refreshRateCFNumber ) {
       
  1021                 SDL_SetError ("Mode has no refresh rate");
       
  1022                 goto ERROR;
       
  1023             }
       
  1024             
       
  1025             if ( 0 == CFNumberGetValue (refreshRateCFNumber, kCFNumberDoubleType, &refreshRate) ) {
       
  1026                 SDL_SetError ("Error getting refresh rate");
       
  1027                 goto ERROR;
       
  1028             }
       
  1029             
       
  1030             if ( 0 == refreshRate ) {
       
  1031                
       
  1032                SDL_SetError ("Display has no refresh rate, using 60hz");
       
  1033                 
       
  1034                 /* ok, for LCD's we'll emulate a 60hz refresh, which may or may not look right */
       
  1035                 refreshRate = 60.0;
       
  1036             }
       
  1037             
       
  1038             linesPerSecond = refreshRate * h;
       
  1039             target = h;
       
  1040         
       
  1041             /* Figure out the first delay so we start off about right */
       
  1042             position = CGDisplayBeamPosition (display_id);
       
  1043             if (position > target)
       
  1044                 position = 0;
       
  1045             
       
  1046             adjustment = (target - position) / linesPerSecond; 
       
  1047             
       
  1048             nextTime = AddAbsoluteToAbsolute (UpTime (), QZ_SecondsToAbsolute (adjustment));
       
  1049         
       
  1050             MPDelayUntil (&nextTime);
       
  1051         }
       
  1052         
       
  1053         
       
  1054         /* On error, skip VBL delay */
       
  1055         ERROR:
       
  1056         
       
  1057         /* TODO: use CGContextDrawImage here too!  Create two CGContextRefs the same way we
       
  1058            create two buffers, replace current_buffer with current_context and set it
       
  1059            appropriately in QZ_FlipDoubleBuffer.  */
       
  1060         while ( h-- ) {
       
  1061         
       
  1062             SDL_memcpy (dst, src, len);
       
  1063             src += skip;
       
  1064             dst += skip;
       
  1065         }
       
  1066         
       
  1067         /* signal flip completion */
       
  1068         SDL_SemPost (sem2);
       
  1069     }
       
  1070     
       
  1071     return 0;
       
  1072 }
       
  1073         
       
  1074 static int QZ_FlipDoubleBuffer (_THIS, SDL_Surface *surface)
       
  1075 {
       
  1076     /* wait for previous flip to complete */
       
  1077     SDL_SemWait (sem2);
       
  1078     
       
  1079     current_buffer = surface->pixels;
       
  1080         
       
  1081     if (surface->pixels == sw_buffers[0])
       
  1082         surface->pixels = sw_buffers[1];
       
  1083     else
       
  1084         surface->pixels = sw_buffers[0];
       
  1085     
       
  1086     /* signal worker thread to do the flip */
       
  1087     SDL_SemPost (sem1);
       
  1088     
       
  1089     return 0;
       
  1090 }
       
  1091 
       
  1092 static void QZ_DoubleBufferUpdate (_THIS, int num_rects, SDL_Rect *rects)
       
  1093 {
       
  1094     /* perform a flip if someone calls updaterects on a doublebuferred surface */
       
  1095     this->FlipHWSurface (this, SDL_VideoSurface);
       
  1096 }
       
  1097 
       
  1098 static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *rects)
       
  1099 {
       
  1100 #pragma unused(this,num_rects,rects)
       
  1101 }
   891 }
  1102 
   892 
  1103 
   893 
  1104 /* Resize icon, BMP format */
   894 /* Resize icon, BMP format */
  1105 static const unsigned char QZ_ResizeIcon[] = {
   895 static const unsigned char QZ_ResizeIcon[] = {
  1235         [field_edit release];
  1025         [field_edit release];
  1236         field_edit = NULL;
  1026         field_edit = NULL;
  1237     }
  1027     }
  1238 }
  1028 }
  1239 
  1029 
  1240 #if 0 /* Not used (apparently, it's really slow) */
       
  1241 static int  QZ_FillHWRect (_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color)
       
  1242 {
       
  1243     CGSDisplayHWFill (display_id, rect->x, rect->y, rect->w, rect->h, color);
       
  1244 
       
  1245     return 0;
       
  1246 }
       
  1247 #endif
       
  1248 
       
  1249 static int  QZ_LockHWSurface(_THIS, SDL_Surface *surface)
  1030 static int  QZ_LockHWSurface(_THIS, SDL_Surface *surface)
  1250 {
  1031 {
  1251     /*
       
  1252      * Always get latest bitmap address and rowbytes for the screen surface;
       
  1253      *  they can change dynamically (user has multiple monitors, etc).
       
  1254      */
       
  1255     if ((surface == SDL_VideoSurface) && (surface->flags & SDL_HWSURFACE)) {
       
  1256         surface->pixels = (void*) CGDisplayBaseAddress (kCGDirectMainDisplay);
       
  1257         surface->pitch  = CGDisplayBytesPerRow (kCGDirectMainDisplay);
       
  1258         return (surface->pixels != NULL);
       
  1259     }
       
  1260 
       
  1261     return 1;
  1032     return 1;
  1262 }
  1033 }
  1263 
  1034 
  1264 static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface)
  1035 static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface)
  1265 {
  1036 {
  1271 }
  1042 }
  1272 
  1043 
  1273 static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface)
  1044 static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface)
  1274 {
  1045 {
  1275 }
  1046 }
  1276 
       
  1277 /*
       
  1278  int QZ_FlipHWSurface (_THIS, SDL_Surface *surface) {
       
  1279      return 0;
       
  1280  }
       
  1281  */
       
  1282 
  1047 
  1283 /* Gamma functions */
  1048 /* Gamma functions */
  1284 int QZ_SetGamma (_THIS, float red, float green, float blue)
  1049 int QZ_SetGamma (_THIS, float red, float green, float blue)
  1285 {
  1050 {
  1286     const CGGammaValue min = 0.0, max = 1.0;
  1051     const CGGammaValue min = 0.0, max = 1.0;