After a little discussion on the list, I made this patch for cocoa.m, to replace CoreGraphic by OpenGL.

It's way faster than CG, but it requires a Mac with OpenGL capable Graphics Card and at least 8mb of VRAM.
I think starting with G4 and Highend G3, this requirements are met.

features:
[new] draws dirty lines of the window as needed, implemented with OpenGL (used the extensions as proposed by Pierre)
[new] window can be resized
[fix] conditional builds for Leopard, without linking to a specific sdk
[fix] lineflicker in fullscreen mode

The Question is, where to draw the line - or - if it needs a switch for CG/OpenGL support for cocoa.

Please test and comment.

 Mike

[1] http://www.kberg.ch/qemu/091patches/cocoa_m_OpenGL.diff.gz





--- /Users/mike/Documents/Qemu091gcc4/qemu/cocoa.m_original.m 2008-01-21 17:11:30.000000000 +0100 +++ /Users/mike/Documents/Qemu091gcc4/qemu/cocoa.m 2008-02-01 17:11:41.000000000 +0100
@@ -22,12 +22,17 @@
  * THE SOFTWARE.
  */

+#include <AvailabilityMacros.h>
+
 #import <Cocoa/Cocoa.h>

+#import <OpenGL/gl.h>
+
 #include "qemu-common.h"
 #include "console.h"
 #include "sysemu.h"

+#define titleBarHeight 21.0

 //#define DEBUG

@@ -54,6 +59,16 @@
     int bitsPerPixel;
 } QEMUScreen;

+typedef struct {
+    float x;
+    float y;
+    float width;
+    float height;
+    float dx;
+    float dy;
+    float zoom;
+} COCOADisplayProperties;
+
 int qemu_main(int argc, char **argv); // main defined in qemu/vl.c
 NSWindow *normalWindow;
 id cocoaView;
@@ -246,18 +261,19 @@
     QemuCocoaView
  ------------------------------------------------------
 */
[EMAIL PROTECTED] QemuCocoaView : NSView
[EMAIL PROTECTED] QemuCocoaView : NSOpenGLView
 {
     QEMUScreen screen;
+    COCOADisplayProperties displayProperties;
     NSWindow *fullScreenWindow;
-    float cx,cy,cw,ch,cdx,cdy;
-    CGDataProviderRef dataProviderRef;
+    GLuint screen_tex;
     int modifiers_state[256];
     BOOL isMouseGrabed;
     BOOL isFullscreen;
     BOOL isAbsoluteEnabled;
     BOOL isTabletEnabled;
 }
+- (void) setContentDimensionsForFrame:(NSRect)rect;
- (void) resizeContentToWidth:(int)w height:(int)h displayState: (DisplayState *)ds;
 - (void) grabMouse;
 - (void) ungrabMouse;
@@ -266,17 +282,16 @@
 - (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled;
 - (BOOL) isMouseGrabed;
 - (BOOL) isAbsoluteEnabled;
-- (float) cdx;
-- (float) cdy;
 - (QEMUScreen) gscreen;
+- (COCOADisplayProperties) displayProperties;
 @end

 @implementation QemuCocoaView
-- (id)initWithFrame:(NSRect)frameRect
+- (id)initWithFrame:(NSRect)frameRect pixelFormat: (NSOpenGLPixelFormat *)format
 {
-    COCOA_DEBUG("QemuCocoaView: initWithFrame\n");
+    COCOA_DEBUG("QemuCocoaView: initWithFrame:pixelFormat\n");

-    self = [super initWithFrame:frameRect];
+    self = [super initWithFrame:frameRect pixelFormat:format];
     if (self) {

         screen.bitsPerComponent = 8;
@@ -284,6 +299,8 @@
         screen.width = frameRect.size.width;
         screen.height = frameRect.size.height;

+        displayProperties.zoom = 1.0;
+
     }
     return self;
 }
@@ -295,110 +312,118 @@
     if (screenBuffer)
         free(screenBuffer);

-    if (dataProviderRef)
-        CGDataProviderRelease(dataProviderRef);
-
     [super dealloc];
 }

 - (void) drawRect:(NSRect) rect
 {
-    COCOA_DEBUG("QemuCocoaView: drawRect\n");
+ COCOA_DEBUG("QemuCocoaView: drawRect: NSRect(%f, %f, %f, %f)\n", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);

     if ((int)screenBuffer == -1)
         return;

-    // get CoreGraphic context
- CGContextRef viewContextRef = [[NSGraphicsContext currentContext] graphicsPort]; - CGContextSetInterpolationQuality (viewContextRef, kCGInterpolationNone);
-    CGContextSetShouldAntialias (viewContextRef, NO);
-
-    // draw screen bitmap directly to Core Graphics context
-    if (dataProviderRef) {
-        CGImageRef imageRef = CGImageCreate(
-            screen.width, //width
-            screen.height, //height
-            screen.bitsPerComponent, //bitsPerComponent
-            screen.bitsPerPixel, //bitsPerPixel
-            (screen.width * 4), //bytesPerRow
+    // remove old texture
+    if( screen_tex != 0) {
+        glDeleteTextures(1, &screen_tex);
+    }
+
+    screen_tex = 1;
+    float onePixel[2];
+    onePixel[0] = 2.0 / displayProperties.width;
+    onePixel[1] = 2.0 / displayProperties.height;
+
+    //calculate the texure rect
+    NSRect clipRect;
+    clipRect = NSMakeRect(
+ 0.0, // we update the whole width, as QEMU in vga is always updating whole memory pages) + floor((float)screen.height - (rect.origin.y + rect.size.height) / displayProperties.dy),
+        (float)screen.width,
+        ceil(rect.size.height / displayProperties.dy));
+    int start = (int)clipRect.origin.y * screen.width * 4;
+    unsigned char *startPointer = screenBuffer;
+
+    //adapt the drawRect to the textureRect
+    rect = NSMakeRect(
+ 0.0, // we update the whole width, as QEMU in vga is always updating whole memory pages) + (screen.height - (clipRect.origin.y + clipRect.size.height)) * displayProperties.dy,
+        displayProperties.width,
+        clipRect.size.height * displayProperties.dy);
+
+    glEnable(GL_TEXTURE_RECTANGLE_ARB); // enable rectangle textures
+
+    // bind screenBuffer to texture
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, screen.width); // Sets the appropriate unpacking row length for the bitmap. + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Sets the byte-aligned unpacking that's needed for bitmaps that are 3 bytes per pixel.
+
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, screen_tex); // Binds the texture name to the texture target. + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Sets filtering so that it does not use a mipmap, which would be redundant for the texture rectangle extension
+
+    // optimize loading of texture
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_SHARED_APPLE); // + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); // bypass OpenGL framework + glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_EXT, (int)clipRect.size.height * screen.width * 4, &startPointer[start]); // bypass OpenGL driver
+
+    glTexImage2D(
+        GL_TEXTURE_RECTANGLE_ARB,
+        0,
+        GL_RGBA,
+        screen.width,
+        (int)clipRect.size.height,
+        0,
 #if __LITTLE_ENDIAN__
- CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), // colorspace for OS X >= 10.4
-            kCGImageAlphaNoneSkipLast,
+        GL_RGBA,
+        GL_UNSIGNED_BYTE,
 #else
- CGColorSpaceCreateDeviceRGB(), //colorspace for OS X < 10.4 (actually ppc)
-            kCGImageAlphaNoneSkipFirst, //bitmapInfo
-#endif
-            dataProviderRef, //provider
-            NULL, //decode
-            0, //interpolate
-            kCGRenderingIntentDefault //intent
-        );
-// test if host support "CGImageCreateWithImageInRect" at compiletime
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
- if (CGImageCreateWithImageInRect == NULL) { // test if "CGImageCreateWithImageInRect" is supported on host at runtime
+        GL_BGRA,
+        GL_UNSIGNED_INT_8_8_8_8_REV,
 #endif
- // compatibility drawing code (draws everything) (OS X < 10.4) - CGContextDrawImage (viewContextRef, CGRectMake(0, 0, [self bounds].size.width, [self bounds].size.height), imageRef);
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
-        } else {
- // selective drawing code (draws only dirty rectangles) (OS X >= 10.4)
-            const NSRect *rectList;
-            int rectCount;
-            int i;
-            CGImageRef clipImageRef;
-            CGRect clipRect;
-
-            [self getRectsBeingDrawn:&rectList count:&rectCount];
-            for (i = 0; i < rectCount; i++) {
-                clipRect.origin.x = rectList[i].origin.x / cdx;
- clipRect.origin.y = (float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy;
-                clipRect.size.width = rectList[i].size.width / cdx;
-                clipRect.size.height = rectList[i].size.height / cdy;
-                clipImageRef = CGImageCreateWithImageInRect(
-                    imageRef,
-                    clipRect
-                );
- CGContextDrawImage (viewContextRef, cgrect(rectList[i]), clipImageRef);
-                CGImageRelease (clipImageRef);
-            }
-        }
-#endif
-        CGImageRelease (imageRef);
+        &startPointer[start]);
+
+    glBegin(GL_QUADS);
+    {
+    glTexCoord2f(0.0f, 0.0f);
+ glVertex2f(-1.0f, (GLfloat)(onePixel[1] * (rect.origin.y + rect.size.height) - 1.0));
+
+    glTexCoord2f(0.0f, (GLfloat)clipRect.size.height);
+    glVertex2f(-1.0f, (GLfloat)(onePixel[1] * rect.origin.y - 1.0));
+
+ glTexCoord2f((GLfloat)clipRect.size.width, (GLfloat)clipRect.size.height);
+    glVertex2f(1.0f, (GLfloat)(onePixel[1] * rect.origin.y - 1.0));
+
+    glTexCoord2f((GLfloat)clipRect.size.width, 0.0f);
+ glVertex2f(1.0f, (GLfloat)(onePixel[1] * (rect.origin.y + rect.size.height) - 1.0));
     }
+    glEnd();
+
+    glFlush();
 }

-- (void) setContentDimensions
+- (void) setContentDimensionsForFrame:(NSRect)rect
 {
-    COCOA_DEBUG("QemuCocoaView: setContentDimensions\n");
+ COCOA_DEBUG("QemuCocoaView: setContentDimensionsForFrame: NSRect(%f, %f, %f, %f)\n", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);

-    if (isFullscreen) {
- cdx = [[NSScreen mainScreen] frame].size.width / (float)screen.width; - cdy = [[NSScreen mainScreen] frame].size.height / (float)screen.height;
-        cw = screen.width * cdx;
-        ch = screen.height * cdy;
-        cx = ([[NSScreen mainScreen] frame].size.width - cw) / 2.0;
-        cy = ([[NSScreen mainScreen] frame].size.height - ch) / 2.0;
-    } else {
-        cx = 0;
-        cy = 0;
-        cw = screen.width;
-        ch = screen.height;
-        cdx = 1.0;
-        cdy = 1.0;
-    }
+    displayProperties.dx = rect.size.width / (float)screen.width;
+    displayProperties.dy = rect.size.height / (float)screen.height;
+    displayProperties.width = rect.size.width;
+    displayProperties.height = rect.size.height;
+    displayProperties.x = 0.0;//([self bounds].size.width - cw) / 2.0;
+    displayProperties.y = 0.0;//([self bounds].size.height - ch) / 2.0;
+
+    [[self openGLContext] makeCurrentContext];
+ glViewport(displayProperties.x, displayProperties.y, displayProperties.width, displayProperties.height);
+    [self update];
 }

- (void) resizeContentToWidth:(int)w height:(int)h displayState: (DisplayState *)ds
 {
-    COCOA_DEBUG("QemuCocoaView: resizeContent\n");
+ COCOA_DEBUG("QemuCocoaView: resizeContentToWidth:%i height:%i\n", w, h);

     // update screenBuffer
-    if (dataProviderRef)
-        CGDataProviderRelease(dataProviderRef);
     if (screenBuffer)
         free(screenBuffer);
     screenBuffer = malloc( w * 4 * h );

+    // update display state
     ds->data = screenBuffer;
     ds->linesize =  (w * 4);
     ds->depth = 32;
@@ -410,21 +435,31 @@
     ds->bgr = 0;
 #endif

- dataProviderRef = CGDataProviderCreateWithData(NULL, screenBuffer, w * 4 * h, NULL);
+    // update screen state
+    screen.width = w;
+    screen.height = h;
+
+    NSSize normalWindowSize;
+    normalWindowSize = NSMakeSize(
+        (float)w * displayProperties.zoom,
+        (float)h * displayProperties.zoom + titleBarHeight
+    );
+
+    // keep Window in correct aspect ratio
+ [normalWindow setMaxSize:NSMakeSize(normalWindowSize.width, normalWindowSize.height)]; + [normalWindow setAspectRatio:NSMakeSize(normalWindowSize.width, normalWindowSize.height)];

     // update windows
     if (isFullscreen) {
- [[fullScreenWindow contentView] setFrame:[[NSScreen mainScreen] frame]]; - [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:NO animate:NO]; + [self setContentDimensionsForFrame:[[NSScreen mainScreen] frame]]; + [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y + [normalWindow frame].size.height - normalWindowSize.height, normalWindowSize.width, normalWindowSize.height) display:NO animate:NO];
     } else {
         if (qemu_name)
[normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]]; - [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:YES animate:YES]; + [self setContentDimensionsForFrame:NSMakeRect(0, 0, w * displayProperties.zoom, h * displayProperties.zoom)]; + [self setFrame:NSMakeRect(0, 0, w * displayProperties.zoom, h * displayProperties.zoom)]; + [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y + [normalWindow frame].size.height - normalWindowSize.height, normalWindowSize.width, normalWindowSize.height) display:YES animate:YES];
     }
-    screen.width = w;
-    screen.height = h;
-    [self setContentDimensions];
-    [self setFrame:NSMakeRect(cx, cy, cw, ch)];
 }

 - (void) toggleFullScreen:(id)sender
@@ -434,9 +469,8 @@
     if (isFullscreen) { // switch from fullscreen to desktop
         isFullscreen = FALSE;
         [self ungrabMouse];
-        [self setContentDimensions];
// test if host support "enterFullScreenMode:withOptions" at compiletime
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
+#ifdef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
if ([NSView respondsToSelector:@selector(exitFullScreenModeWithOptions:)]) { // test if "exitFullScreenModeWithOptions" is supported on host at runtime
             [self exitFullScreenModeWithOptions:nil];
         } else {
@@ -445,15 +479,16 @@
             [normalWindow setContentView: self];
             [normalWindow makeKeyAndOrderFront: self];
             [NSMenu setMenuBarVisible:YES];
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
+#ifdef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
         }
 #endif
+ [self setContentDimensionsForFrame:NSMakeRect(0.0, 0.0, screen.width * displayProperties.zoom, screen.height * displayProperties.zoom)];
     } else { // switch from desktop to fullscreen
         isFullscreen = TRUE;
         [self grabMouse];
-        [self setContentDimensions];
+ [self setContentDimensionsForFrame:NSMakeRect(0.0, 0.0, [[NSScreen mainScreen] frame].size.width, [[NSScreen mainScreen] frame].size.height)]; // test if host support "enterFullScreenMode:withOptions" at compiletime
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
+#ifdef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
if ([NSView respondsToSelector:@selector(enterFullScreenMode:withOptions:)]) { // test if "enterFullScreenMode:withOptions" is supported on host at runtime [self enterFullScreenMode:[NSScreen mainScreen] withOptions:[NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:NO], NSFullScreenModeAllScreens,
@@ -469,7 +504,7 @@
             [fullScreenWindow setHasShadow:NO];
             [fullScreenWindow setContentView:self];
             [fullScreenWindow makeKeyAndOrderFront:self];
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
+#ifdef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
         }
 #endif
     }
@@ -581,7 +616,7 @@
             break;
         case NSMouseMoved:
             if (isAbsoluteEnabled) {
- if (p.x < 0 || p.x > screen.width || p.y < 0 || p.y > screen.height || ![[self window] isKeyWindow]) { + if (p.x < 0 || p.x > (screen.width * displayProperties.zoom) || p.y < 0 || p.y > (screen.height * displayProperties.zoom) || ![[self window] isKeyWindow]) { if (isTabletEnabled) { // if we leave the window, deactivate the tablet
                         [NSCursor unhide];
                         isTabletEnabled = FALSE;
@@ -688,12 +723,42 @@
     isMouseGrabed = FALSE;
 }

+- (NSSize)windowWillResize:(NSWindow *)window toSize: (NSSize)proposedFrameSize
+{
+ COCOA_DEBUG("QemuCocoaView: windowWillResize: toSize: NSSize(%f, %f)\n", proposedFrameSize.width, proposedFrameSize.height);
+
+    // update zoom
+ displayProperties.zoom = proposedFrameSize.width / (float)screen.width;
+
+ // Update the content to new size before window is resized, if the new size is bigger + if (proposedFrameSize.width > [window frame].size.width || proposedFrameSize.height > [window frame].size.height) { + [self setContentDimensionsForFrame:NSMakeRect(0, 0, proposedFrameSize.width, proposedFrameSize.height - titleBarHeight)]; + [self setFrame:NSMakeRect(displayProperties.x, displayProperties.y, displayProperties.width, displayProperties.height - titleBarHeight)];
+    }
+
+    return proposedFrameSize;
+}
+
+- (void)windowDidResize:(NSNotification *)notification
+{
+    COCOA_DEBUG("QemuCocoaView: windowDidResize\n");
+
+    // update the content, if the size has changed
+ if (displayProperties.width != [[self window] frame].size.width || displayProperties.height != [[self window] frame].size.height - titleBarHeight) {
+        if (isFullscreen) {
+ [self setContentDimensionsForFrame:NSMakeRect(0, 0, [[self window] frame].size.width, [[self window] frame].size.height)];
+        } else {
+ [self setContentDimensionsForFrame:NSMakeRect(0, 0, [[self window] frame].size.width, [[self window] frame].size.height - titleBarHeight)];
+        }
+ [self setFrame:NSMakeRect(displayProperties.x, displayProperties.y, displayProperties.width, displayProperties.height)];
+    }
+}
+
- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;}
 - (BOOL) isMouseGrabed {return isMouseGrabed;}
 - (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;}
-- (float) cdx {return cdx;}
-- (float) cdy {return cdy;}
 - (QEMUScreen) gscreen {return screen;}
+- (COCOADisplayProperties) displayProperties {return displayProperties;}
 @end


@@ -722,7 +787,7 @@
     if (self) {

         // create a view and add it to the window
- cocoaView = [[QemuCocoaView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 640.0, 480.0)]; + cocoaView = [[QemuCocoaView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 640.0, 480.0) pixelFormat: [NSOpenGLView defaultPixelFormat]];
         if(!cocoaView) {
             fprintf(stderr, "(cocoa) can't create a view\n");
             exit(1);
@@ -730,7 +795,7 @@

         // create a window
normalWindow = [[NSWindow alloc] initWithContentRect: [cocoaView frame] - styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask| NSClosableWindowMask + styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask| NSClosableWindowMask|NSResizableWindowMask
             backing:NSBackingStoreBuffered defer:NO];
         if(!normalWindow) {
             fprintf(stderr, "(cocoa) can't create window\n");
@@ -740,6 +805,7 @@
         [normalWindow setTitle:[NSString stringWithFormat:@"QEMU"]];
         [normalWindow setContentView:cocoaView];
         [normalWindow makeKeyAndOrderFront:self];
+        [normalWindow setDelegate:cocoaView];

     }
     return self;
@@ -927,15 +993,12 @@
     COCOA_DEBUG("qemu_cocoa: cocoa_update\n");

     NSRect rect;
-    if ([cocoaView cdx] == 1.0) {
-        rect = NSMakeRect(x, [cocoaView gscreen].height - y - h, w, h);
-    } else {
-        rect = NSMakeRect(
-            x * [cocoaView cdx],
-            ([cocoaView gscreen].height - y - h) * [cocoaView cdy],
-            w * [cocoaView cdx],
-            h * [cocoaView cdy]);
-    }
+    rect = NSMakeRect(
+        x * [cocoaView displayProperties].dx,
+ ([cocoaView gscreen].height - y - h) * [cocoaView displayProperties].dy,
+        w * [cocoaView displayProperties].dx,
+        h * [cocoaView displayProperties].dy);
+
     [cocoaView displayRect:rect];
 }

--- /Users/mike/Documents/Qemu091gcc4/qemu/configure_original 2008-02-01 09:27:49.000000000 +0100 +++ /Users/mike/Documents/Qemu091gcc4/qemu/configure 2008-02-01 09:33:37.000000000 +0100
@@ -154,7 +154,7 @@
 cocoa="yes"
 coreaudio="yes"
 OS_CFLAGS="-mdynamic-no-pic"
-OS_LDFLAGS="-framework CoreFoundation -framework IOKit"
+OS_LDFLAGS="-framework CoreFoundation -framework IOKit -framework OpenGL"
 ;;
 SunOS)
     solaris="yes"
--- /Users/mike/Documents/Qemu091gcc4/qemu/Makefile.target_original 2008-02-01 09:38:48.000000000 +0100 +++ /Users/mike/Documents/Qemu091gcc4/qemu/Makefile.target 2008-02-01 09:38:32.000000000 +0100
@@ -525,7 +525,7 @@
 VL_OBJS+=gdbstub.o
 endif
 ifdef CONFIG_COCOA
-COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit +COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit -framework OpenGL
 ifdef CONFIG_COREAUDIO
 COCOA_LIBS+=-framework CoreAudio
 endif

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to