[PATCH 4/5] winemac.drv: Set the surface contents directly to the layer.
Chip Davis
cdavis at codeweavers.com
Tue Aug 31 17:27:36 CDT 2021
Use a top-down DIB for the surface instead of a bottom-up DIB. This
seems to match better with how Core Graphics expects to receive image
data, and allows us to avoid a transform to flip the surface image.
Unfortunately, it requires us to use a transform to flip the image
in the -drawRect: path. We'll be getting rid of that in the next patch,
though.
Signed-off-by: Chip Davis <cdavis at codeweavers.com>
---
dlls/winemac.drv/cocoa_window.m | 86 ++++++++++++++++++++++++++-------
dlls/winemac.drv/macdrv_cocoa.h | 3 +-
dlls/winemac.drv/surface.c | 42 +++++++++++-----
3 files changed, 101 insertions(+), 30 deletions(-)
diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m
index 3eb8ec20877..75fc26bbcf8 100644
--- a/dlls/winemac.drv/cocoa_window.m
+++ b/dlls/winemac.drv/cocoa_window.m
@@ -491,6 +491,54 @@ - (BOOL) isFlipped
return YES;
}
+ - (BOOL) wantsUpdateLayer
+ {
+ return YES /*!_everHadGLContext*/;
+ }
+
+ - (void) updateLayer
+ {
+ WineWindow* window = (WineWindow*)[self window];
+ CGImageRef image = NULL;
+ CGRect imageRect;
+ CALayer* layer = [self layer];
+
+ if ([window contentView] != self)
+ return;
+
+ if (!window.surface || !window.surface_mutex)
+ return;
+
+ pthread_mutex_lock(window.surface_mutex);
+ if (get_surface_blit_rects(window.surface, NULL, NULL))
+ {
+ imageRect = layer.bounds;
+ imageRect.origin.x *= layer.contentsScale;
+ imageRect.origin.y *= layer.contentsScale;
+ imageRect.size.width *= layer.contentsScale;
+ imageRect.size.height *= layer.contentsScale;
+ image = create_surface_image(window.surface, &imageRect, FALSE, window.colorKeyed,
+ window.colorKeyRed, window.colorKeyGreen, window.colorKeyBlue);
+ }
+ pthread_mutex_unlock(window.surface_mutex);
+
+ if (image)
+ {
+ 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 (window.colorKeyed || window.usePerPixelAlpha || window.shapeChangedSinceLastDraw)
+ {
+ window.shapeChangedSinceLastDraw = FALSE;
+ [window invalidateShadow];
+ }
+ }
+ }
+
- (void) viewWillDraw
{
[super viewWillDraw];
@@ -521,12 +569,17 @@ - (void) drawRect:(NSRect)rect
const CGRect* rects;
int count;
- if (get_surface_blit_rects(window.surface, &rects, &count) && count)
+ if (get_surface_blit_rects(window.surface, &rects, &count))
{
CGRect dirtyRect = cgrect_win_from_mac(NSRectToCGRect(rect));
+ NSAffineTransform* xform = [NSAffineTransform transform];
CGContextRef context;
int i;
+ [xform translateXBy:0.0 yBy:self.bounds.size.height];
+ [xform scaleXBy:1.0 yBy:-1.0];
+ [xform concat];
+
context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGContextSetInterpolationQuality(context, retina_on ? kCGInterpolationHigh : kCGInterpolationNone);
@@ -537,25 +590,15 @@ - (void) drawRect:(NSRect)rect
CGImageRef image;
imageRect = CGRectIntersection(rects[i], dirtyRect);
- image = create_surface_image(window.surface, &imageRect, FALSE);
+ image = create_surface_image(window.surface, &imageRect, FALSE, window.colorKeyed,
+ window.colorKeyRed, window.colorKeyGreen, window.colorKeyBlue);
if (image)
{
- if (window.colorKeyed)
- {
- CGImageRef maskedImage;
- CGFloat components[] = { window.colorKeyRed - 0.5, window.colorKeyRed + 0.5,
- window.colorKeyGreen - 0.5, window.colorKeyGreen + 0.5,
- window.colorKeyBlue - 0.5, window.colorKeyBlue + 0.5 };
- maskedImage = CGImageCreateWithMaskingColors(image, components);
- if (maskedImage)
- {
- CGImageRelease(image);
- image = maskedImage;
- }
- }
-
- CGContextDrawImage(context, cgrect_mac_from_win(imageRect), image);
+ // Account for the flipped coordinate system.
+ imageRect = cgrect_mac_from_win(imageRect);
+ imageRect.origin.y = self.bounds.size.height - imageRect.origin.y - imageRect.size.height;
+ CGContextDrawImage(context, imageRect, image);
CGImageRelease(image);
}
@@ -708,6 +751,9 @@ - (void) setRetinaMode:(int)mode
[self updateGLContexts];
_retinaMode = !!mode;
+ [self layer].contentsScale = mode ? 2.0 : 1.0;
+ [self layer].minificationFilter = mode ? kCAFilterLinear : kCAFilterNearest;
+ [self layer].magnificationFilter = mode ? kCAFilterLinear : kCAFilterNearest;
[super setRetinaMode:mode];
}
@@ -1028,6 +1074,9 @@ + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)w
if (!contentView)
return nil;
[contentView setWantsLayer:YES];
+ [contentView layer].minificationFilter = retina_on ? kCAFilterLinear : kCAFilterNearest;
+ [contentView layer].magnificationFilter = retina_on ? kCAFilterLinear : kCAFilterNearest;
+ [contentView layer].contentsScale = retina_on ? 2.0 : 1.0;
[contentView setAutoresizesSubviews:NO];
/* We use tracking areas in addition to setAcceptsMouseMovedEvents:YES
@@ -3599,6 +3648,9 @@ macdrv_view macdrv_create_view(CGRect rect)
view = [[WineContentView alloc] initWithFrame:NSRectFromCGRect(cgrect_mac_from_win(rect))];
[view setWantsLayer:YES];
+ [view layer].minificationFilter = retina_on ? kCAFilterLinear : kCAFilterNearest;
+ [view layer].magnificationFilter = retina_on ? kCAFilterLinear : kCAFilterNearest;
+ [view layer].contentsScale = retina_on ? 2.0 : 1.0;
[view setAutoresizesSubviews:NO];
[view setAutoresizingMask:NSViewNotSizable];
[view setHidden:YES];
diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h
index b02ad79f025..47ae6627b9f 100644
--- a/dlls/winemac.drv/macdrv_cocoa.h
+++ b/dlls/winemac.drv/macdrv_cocoa.h
@@ -566,7 +566,8 @@ extern void macdrv_order_cocoa_window(macdrv_window w, macdrv_window prev,
extern void macdrv_get_cocoa_window_frame(macdrv_window w, CGRect* out_frame) DECLSPEC_HIDDEN;
extern void macdrv_set_cocoa_parent_window(macdrv_window w, macdrv_window parent) DECLSPEC_HIDDEN;
extern void macdrv_set_window_surface(macdrv_window w, void *surface, pthread_mutex_t *mutex) DECLSPEC_HIDDEN;
-extern CGImageRef create_surface_image(void *window_surface, CGRect *rect, int copy_data) DECLSPEC_HIDDEN;
+extern CGImageRef create_surface_image(void *window_surface, CGRect *rect, int copy_data, int color_keyed,
+ CGFloat key_red, CGFloat key_green, CGFloat key_blue) DECLSPEC_HIDDEN;
extern int get_surface_blit_rects(void *window_surface, const CGRect **rects, int *count) DECLSPEC_HIDDEN;
extern void macdrv_window_needs_display(macdrv_window w, CGRect rect) DECLSPEC_HIDDEN;
extern void macdrv_set_window_shape(macdrv_window w, const CGRect *rects, int count) DECLSPEC_HIDDEN;
diff --git a/dlls/winemac.drv/surface.c b/dlls/winemac.drv/surface.c
index 7be1b6850e0..6a5cd535923 100644
--- a/dlls/winemac.drv/surface.c
+++ b/dlls/winemac.drv/surface.c
@@ -264,7 +264,7 @@ struct window_surface *create_surface(macdrv_window window, const RECT *rect,
surface->info.bmiHeader.biSize = sizeof(surface->info.bmiHeader);
surface->info.bmiHeader.biWidth = width;
- surface->info.bmiHeader.biHeight = height; /* bottom-up */
+ surface->info.bmiHeader.biHeight = -height; /* top-down */
surface->info.bmiHeader.biPlanes = 1;
surface->info.bmiHeader.biBitCount = 32;
surface->info.bmiHeader.biSizeImage = get_dib_image_size(&surface->info);
@@ -342,18 +342,21 @@ int get_surface_blit_rects(void *window_surface, const CGRect **rects, int *coun
{
struct macdrv_window_surface *surface = get_mac_surface(window_surface);
- if (surface->blit_data)
+ if (rects && count)
{
- *rects = (const CGRect*)surface->blit_data->Buffer;
- *count = surface->blit_data->rdh.nCount;
- }
- else
- {
- *rects = NULL;
- *count = 0;
+ if (surface->blit_data)
+ {
+ *rects = (const CGRect*)surface->blit_data->Buffer;
+ *count = surface->blit_data->rdh.nCount;
+ }
+ else
+ {
+ *rects = NULL;
+ *count = 0;
+ }
}
- return (surface->blit_data != NULL);
+ return (surface->blit_data != NULL && surface->blit_data->rdh.nCount > 0);
}
/***********************************************************************
@@ -371,7 +374,8 @@ int get_surface_blit_rects(void *window_surface, const CGRect **rects, int *coun
* must not use Win32 or Wine functions, including debug
* logging.
*/
-CGImageRef create_surface_image(void *window_surface, CGRect *rect, int copy_data)
+CGImageRef create_surface_image(void *window_surface, CGRect *rect, int copy_data, int color_keyed,
+ CGFloat key_red, CGFloat key_green, CGFloat key_blue)
{
CGImageRef cgimage = NULL;
struct macdrv_window_surface *surface = get_mac_surface(window_surface);
@@ -392,7 +396,7 @@ CGImageRef create_surface_image(void *window_surface, CGRect *rect, int copy_dat
colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
bytes_per_row = get_dib_stride(width, 32);
- offset = CGRectGetMinX(visrect) * 4 + (height - CGRectGetMaxY(visrect)) * bytes_per_row;
+ offset = CGRectGetMinX(visrect) * 4 + CGRectGetMinY(visrect) * bytes_per_row;
size = min(CGRectGetHeight(visrect) * bytes_per_row,
surface->info.bmiHeader.biSizeImage - offset);
@@ -412,6 +416,20 @@ CGImageRef create_surface_image(void *window_surface, CGRect *rect, int copy_dat
provider, NULL, retina_on, kCGRenderingIntentDefault);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorspace);
+
+ if (color_keyed)
+ {
+ CGImageRef maskedImage;
+ CGFloat components[] = { key_red - 0.5, key_red + 0.5,
+ key_green - 0.5, key_green + 0.5,
+ key_blue - 0.5, key_blue + 0.5 };
+ maskedImage = CGImageCreateWithMaskingColors(cgimage, components);
+ if (maskedImage)
+ {
+ CGImageRelease(cgimage);
+ cgimage = maskedImage;
+ }
+ }
}
return cgimage;
--
2.33.0
More information about the wine-devel
mailing list