From: Marc-Aurel Zent mzent@codeweavers.com
Based on a patch by Brendan Shanks. --- dlls/winemac.drv/Makefile.in | 2 + dlls/winemac.drv/cocoa_window.m | 69 ++++++++------------ dlls/winemac.drv/macdrv_cocoa.h | 6 +- dlls/winemac.drv/surface.c | 110 +++++++++++++++++++++++++------- 4 files changed, 120 insertions(+), 67 deletions(-)
diff --git a/dlls/winemac.drv/Makefile.in b/dlls/winemac.drv/Makefile.in index a9ce7249eb3..0b8996b4a21 100644 --- a/dlls/winemac.drv/Makefile.in +++ b/dlls/winemac.drv/Makefile.in @@ -4,11 +4,13 @@ IMPORTS = uuid rpcrt4 user32 gdi32 win32u DELAYIMPORTS = ole32 shell32 imm32 UNIX_LIBS = \ -lwin32u \ + -framework Accelerate \ -framework AppKit \ -framework Carbon \ -framework CoreVideo \ -framework Foundation \ -framework IOKit \ + -framework IOSurface \ -framework OpenGL \ -framework QuartzCore \ -framework Security \ diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index 05559b75f9f..9ff0596efaa 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -360,8 +360,8 @@ - (id) initWithFrame:(NSRect)frame device:(id<MTLDevice>)device; @interface WineContentView : WineBaseView <NSTextInputClient, NSViewLayerContentScaleDelegate> { CGRect surfaceRect; - CGImageRef colorImage; - CGImageRef shapeImage; + IOSurfaceRef _IOSurface; + BOOL _hasShape;
NSMutableArray* glContexts; NSMutableArray* pendingGlContexts; @@ -495,8 +495,6 @@ - (void) dealloc [markedText release]; [glContexts release]; [pendingGlContexts release]; - CGImageRelease(colorImage); - CGImageRelease(shapeImage); [super dealloc]; }
@@ -529,26 +527,17 @@ - (void) updateLayer imageRect.size.width *= layer.contentsScale; imageRect.size.height *= layer.contentsScale;
- maskedImage = shapeImage ? CGImageCreateWithMask(colorImage, shapeImage) - : CGImageRetain(colorImage); - image = CGImageCreateWithImageInRect(maskedImage, imageRect); - CGImageRelease(maskedImage); + layer.position = surfaceRect.origin; + layer.contents = (id)_IOSurface; + [window windowDidDrawContent];
- if (image) + // If the window may be transparent, then we have to invalidate the + // shadow every time we draw. Also, if this is the first time we've + // drawn since changing from transparent to opaque. + if (_hasShape || window.usePerPixelAlpha || window.shapeChangedSinceLastDraw) { - layer.position = surfaceRect.origin; - layer.contents = (id)image; - CFRelease(image); - [window windowDidDrawContent]; - - // If the window may be transparent, then we have to invalidate the - // shadow every time we draw. Also, if this is the first time we've - // drawn since changing from transparent to opaque. - if (shapeImage || window.usePerPixelAlpha || window.shapeChangedSinceLastDraw) - { - window.shapeChangedSinceLastDraw = FALSE; - [window invalidateShadow]; - } + window.shapeChangedSinceLastDraw = FALSE; + [window invalidateShadow]; } }
@@ -557,21 +546,19 @@ - (void) setSurfaceRect:(CGRect)rect surfaceRect = rect; }
- - (void) setColorImage:(CGImageRef)image + - (void) setIOSurface:(IOSurfaceRef)image { - CGImageRelease(colorImage); - colorImage = CGImageRetain(image); + _IOSurface = image; }
- - (void) setShapeImage:(CGImageRef)image + - (void) setHasShape:(int)has_shape { - CGImageRelease(shapeImage); - shapeImage = CGImageRetain(image); + _hasShape = !!has_shape; }
- - (BOOL) hasShapeImage + - (BOOL) hasShape { - return !!shapeImage; + return _hasShape; }
- (void) viewWillDraw @@ -2066,7 +2053,7 @@ - (void) setDisabled:(BOOL)newValue - (BOOL) needsTransparency { WineContentView *view = self.contentView; - return self.contentView.layer.mask || [view hasShapeImage] || self.usePerPixelAlpha || + return self.contentView.layer.mask || [view hasShape] || self.usePerPixelAlpha || (gl_surface_mode == GL_SURFACE_BEHIND && [view hasGLDescendant]); }
@@ -3519,51 +3506,47 @@ void macdrv_set_cocoa_parent_window(macdrv_window w, macdrv_window parent)
/*********************************************************************** - * macdrv_window_set_color_image + * macdrv_window_set_io_surface * * Push a window surface color pixel update in a specified rect (in non-client * area coordinates). */ -void macdrv_window_set_color_image(macdrv_window w, CGImageRef image, CGRect rect, CGRect dirty) +void macdrv_window_set_io_surface(macdrv_window w, IOSurfaceRef image, CGRect rect, CGRect dirty) { @autoreleasepool { WineWindow* window = (WineWindow*)w;
- CGImageRetain(image); + IOSurfaceIncrementUseCount(image);
OnMainThreadAsync(^{ WineContentView *view = [window contentView];
- [view setColorImage:image]; + [view setIOSurface:image]; [view setSurfaceRect:cgrect_mac_from_win(rect)]; [view setNeedsDisplayInRect:NSRectFromCGRect(cgrect_mac_from_win(dirty))];
- CGImageRelease(image); + IOSurfaceDecrementUseCount(image); }); } }
/*********************************************************************** - * macdrv_window_set_shape_image + * macdrv_window_shape_changed */ -void macdrv_window_set_shape_image(macdrv_window w, CGImageRef image) +void macdrv_window_shape_changed(macdrv_window w, int has_shape) { @autoreleasepool { WineWindow* window = (WineWindow*)w;
- CGImageRetain(image); - OnMainThreadAsync(^{ WineContentView *view = [window contentView];
- [view setShapeImage:image]; + [view setHasShape:has_shape]; [view setNeedsDisplay:true]; [window checkTransparency]; - - CGImageRelease(image); }); } } diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index 9807d4e53fc..b90416dc307 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -56,7 +56,9 @@ #define ShowCursor MacShowCursor #define UnionRect MacUnionRect
+#include <Accelerate/Accelerate.h> #include <ApplicationServices/ApplicationServices.h> +#include <IOSurface/IOSurface.h>
#undef GetCurrentProcess #undef GetCurrentThread @@ -547,8 +549,8 @@ extern void macdrv_order_cocoa_window(macdrv_window w, macdrv_window prev, extern void macdrv_set_cocoa_window_frame(macdrv_window w, const CGRect* new_frame); extern void macdrv_get_cocoa_window_frame(macdrv_window w, CGRect* out_frame); extern void macdrv_set_cocoa_parent_window(macdrv_window w, macdrv_window parent); -extern void macdrv_window_set_color_image(macdrv_window w, CGImageRef image, CGRect rect, CGRect dirty); -extern void macdrv_window_set_shape_image(macdrv_window w, CGImageRef image); +extern void macdrv_window_set_io_surface(macdrv_window w, IOSurfaceRef image, CGRect rect, CGRect dirty); +extern void macdrv_window_shape_changed(macdrv_window w, int has_shape); extern void macdrv_set_window_shape(macdrv_window w, const CGRect *rects, int count); extern void macdrv_set_window_alpha(macdrv_window w, CGFloat alpha); extern void macdrv_window_use_per_pixel_alpha(macdrv_window w, int use_per_pixel_alpha); diff --git a/dlls/winemac.drv/surface.c b/dlls/winemac.drv/surface.c index bf2acf31431..ef5e70bce5b 100644 --- a/dlls/winemac.drv/surface.c +++ b/dlls/winemac.drv/surface.c @@ -48,6 +48,9 @@ struct macdrv_window_surface struct window_surface header; macdrv_window window; CGDataProviderRef provider; + IOSurfaceRef front_buffer; + IOSurfaceRef back_buffer; + BOOL shape_changed; };
static struct macdrv_window_surface *get_mac_surface(struct window_surface *surface); @@ -85,39 +88,72 @@ static BOOL macdrv_surface_flush(struct window_surface *window_surface, const RE CGImageAlphaInfo alpha_info = (window_surface->alpha_mask ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst); CGColorSpaceRef colorspace; CGImageRef image; + IOSurfaceRef io_surface = surface->back_buffer;
- colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); - image = CGImageCreate(color_info->bmiHeader.biWidth, abs(color_info->bmiHeader.biHeight), 8, 32, - color_info->bmiHeader.biSizeImage / abs(color_info->bmiHeader.biHeight), colorspace, - alpha_info | kCGBitmapByteOrder32Little, surface->provider, NULL, retina_on, kCGRenderingIntentDefault); - CGColorSpaceRelease(colorspace); + surface->back_buffer = surface->front_buffer; + surface->front_buffer = io_surface;
- macdrv_window_set_color_image(surface->window, image, cgrect_from_rect(*rect), cgrect_from_rect(*dirty)); - CGImageRelease(image); + { + vImage_Buffer src = { + .data = color_bits, + .height = IOSurfaceGetHeight(io_surface), + .width = IOSurfaceGetWidth(io_surface), + .rowBytes = IOSurfaceGetBytesPerRow(io_surface), + }; + vImage_Buffer dst = { + .data = IOSurfaceGetBaseAddress(io_surface), + .height = IOSurfaceGetHeight(io_surface), + .width = IOSurfaceGetWidth(io_surface), + .rowBytes = IOSurfaceGetBytesPerRow(io_surface), + }; + vImageSelectChannels_ARGB8888(&src, &dst, &dst, 0x8 | 0x4 | 0x2, kvImageNoFlags); + }
- if (shape_changed) + if (shape_changed || surface->shape_changed) { + surface->shape_changed = FALSE; + if (!shape_bits) - macdrv_window_set_shape_image(surface->window, NULL); + { + Pixel_8888 alpha1 = { 0, 0, 0, 255 }; + vImage_Buffer dst = { + .data = IOSurfaceGetBaseAddress(io_surface), + .height = IOSurfaceGetHeight(io_surface), + .width = IOSurfaceGetWidth(io_surface), + .rowBytes = IOSurfaceGetBytesPerRow(io_surface), + }; + vImageOverwriteChannelsWithPixel_ARGB8888(alpha1, &dst, &dst, 0x1, kvImageNoFlags); + } else { const BYTE *src = shape_bits; - CGDataProviderRef provider; - CGImageRef image; - BYTE *dst; - UINT i; + BYTE *dst = IOSurfaceGetBaseAddress(io_surface); + UINT x, y; + UINT src_row_bytes = shape_info->bmiHeader.biSizeImage / abs(shape_info->bmiHeader.biHeight); + + for (y = 0; y < IOSurfaceGetHeight(io_surface); y++) + { + const BYTE *src_row = src + y * src_row_bytes; + BYTE *dst_row = dst + y * IOSurfaceGetBytesPerRow(io_surface); + for (x = 0; x < IOSurfaceGetWidth(io_surface); x++) + { + BYTE bit = (src_row[x / 8] >> (7 - (x % 8))) & 1; + dst_row[x * 4] = bit ? 0 : 255; + } + } + } + }
- if (!(provider = data_provider_create(shape_info->bmiHeader.biSizeImage, (void **)&dst))) return TRUE; - for (i = 0; i < shape_info->bmiHeader.biSizeImage; i++) dst[i] = ~src[i]; /* CGImage mask bits are inverted */ + macdrv_window_set_io_surface(surface->window, io_surface, cgrect_from_rect(*rect), cgrect_from_rect(*dirty));
- image = CGImageMaskCreate(shape_info->bmiHeader.biWidth, abs(shape_info->bmiHeader.biHeight), 1, 1, - shape_info->bmiHeader.biSizeImage / abs(shape_info->bmiHeader.biHeight), - provider, NULL, retina_on); - CGDataProviderRelease(provider); + if (shape_changed) + { + surface->shape_changed = TRUE;
- macdrv_window_set_shape_image(surface->window, image); - CGImageRelease(image); - } + if (!shape_bits) + macdrv_window_shape_changed(surface->window, FALSE); + else + macdrv_window_shape_changed(surface->window, TRUE); }
return TRUE; @@ -132,6 +168,8 @@ static void macdrv_surface_destroy(struct window_surface *window_surface)
TRACE("freeing %p\n", surface); CGDataProviderRelease(surface->provider); + CFRelease(surface->back_buffer); + CFRelease(surface->front_buffer); }
static const struct window_surface_funcs macdrv_surface_funcs = @@ -163,6 +201,7 @@ static struct window_surface *create_surface(HWND hwnd, macdrv_window window, co HBITMAP bitmap = 0; UINT status; void *bits; + IOSurfaceRef io_surface1, io_surface2;
memset(info, 0, sizeof(*info)); info->bmiHeader.biSize = sizeof(info->bmiHeader); @@ -175,6 +214,30 @@ static struct window_surface *create_surface(HWND hwnd, macdrv_window window, co
if (!(provider = data_provider_create(info->bmiHeader.biSizeImage, &bits))) return NULL; window_background = macdrv_window_background_color(); + + { + CFDictionaryRef properties; + CFStringRef keys[] = { kIOSurfaceWidth, kIOSurfaceHeight, kIOSurfaceBytesPerElement, kIOSurfacePixelFormat }; + CFNumberRef values[4]; + uint32_t surfaceWidth = info->bmiHeader.biWidth; + uint32_t surfaceHeight = abs(info->bmiHeader.biHeight); + uint32_t surfaceBytesPerElement = 4; + uint32_t surfacePixelFormat = 'BGRA'; + + values[0] = CFNumberCreate(NULL, kCFNumberSInt32Type, &surfaceWidth); + values[1] = CFNumberCreate(NULL, kCFNumberSInt32Type, &surfaceHeight); + values[2] = CFNumberCreate(NULL, kCFNumberSInt32Type, &surfaceBytesPerElement); + values[3] = CFNumberCreate(NULL, kCFNumberSInt32Type, &surfacePixelFormat); + + properties = CFDictionaryCreate(NULL, (void **)keys, (void **)values, ARRAY_SIZE(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + io_surface1 = IOSurfaceCreate(properties); + io_surface2 = IOSurfaceCreate(properties); + CFRelease(properties); + + memset_pattern4(IOSurfaceGetBaseAddress(io_surface1), &window_background, info->bmiHeader.biSizeImage); + memset_pattern4(IOSurfaceGetBaseAddress(io_surface2), &window_background, info->bmiHeader.biSizeImage); + } + window_background &= 0x00ffffff; memset_pattern4(bits, &window_background, info->bmiHeader.biSizeImage);
@@ -203,6 +266,9 @@ static struct window_surface *create_surface(HWND hwnd, macdrv_window window, co surface = get_mac_surface(window_surface); surface->window = window; surface->provider = provider; + surface->front_buffer = io_surface1; + surface->back_buffer = io_surface2; + surface->shape_changed = FALSE; }
return window_surface;