Kaynağa Gözat

CocoaSpice: add lock for drawing canvas

osy 5 yıl önce
ebeveyn
işleme
08d2912f67
1 değiştirilmiş dosya ile 32 ekleme ve 14 silme
  1. 32 14
      CocoaSpice/CSDisplayMetal.m

+ 32 - 14
CocoaSpice/CSDisplayMetal.m

@@ -52,10 +52,12 @@ static void cs_primary_create(SpiceChannel *channel, gint format,
     CSDisplayMetal *self = (__bridge CSDisplayMetal *)data;
     
     g_assert(format == SPICE_SURFACE_FMT_32_xRGB || format == SPICE_SURFACE_FMT_16_555);
+    dispatch_semaphore_wait(self->_drawLock, DISPATCH_TIME_FOREVER);
     self->_canvasArea = CGRectMake(0, 0, width, height);
     self->_canvasFormat = format;
     self->_canvasStride = stride;
     self->_canvasData = imgdata;
+    dispatch_semaphore_signal(self->_drawLock);
     
     cs_update_monitor_area(channel, NULL, data);
 }
@@ -63,10 +65,13 @@ static void cs_primary_create(SpiceChannel *channel, gint format,
 static void cs_primary_destroy(SpiceDisplayChannel *channel, gpointer data) {
     CSDisplayMetal *self = (__bridge CSDisplayMetal *)data;
     self.ready = NO;
+    
+    dispatch_semaphore_wait(self->_drawLock, DISPATCH_TIME_FOREVER);
     self->_canvasArea = CGRectZero;
     self->_canvasFormat = 0;
     self->_canvasStride = 0;
     self->_canvasData = NULL;
+    dispatch_semaphore_signal(self->_drawLock);
 }
 
 static void cs_invalidate(SpiceChannel *channel,
@@ -226,17 +231,28 @@ static void cs_channel_destroy(SpiceSession *s, SpiceChannel *channel, gpointer
 }
 
 - (UIImage *)screenshot {
-    if (!_canvasData) {
-        return nil;
-    }
+    CGImageRef img;
     CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
-    CGDataProviderRef dataProviderRef = CGDataProviderCreateWithData(NULL, _canvasData, _canvasStride * _canvasArea.size.height, nil);
-    CGImageRef img = CGImageCreate(_canvasArea.size.width, _canvasArea.size.height, 8, 32, _canvasStride, colorSpaceRef, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst, dataProviderRef, NULL, NO, kCGRenderingIntentDefault);
+    
+    dispatch_semaphore_wait(_drawLock, DISPATCH_TIME_FOREVER); // TODO: separate read lock so we don't block texture copy
+    if (_canvasData) { // may be destroyed at this point
+        CGDataProviderRef dataProviderRef = CGDataProviderCreateWithData(NULL, _canvasData, _canvasStride * _canvasArea.size.height, nil);
+        img = CGImageCreate(_canvasArea.size.width, _canvasArea.size.height, 8, 32, _canvasStride, colorSpaceRef, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst, dataProviderRef, NULL, NO, kCGRenderingIntentDefault);
+        CGDataProviderRelease(dataProviderRef);
+    } else {
+        img = NULL;
+    }
+    dispatch_semaphore_signal(_drawLock);
+    
     CGColorSpaceRelease(colorSpaceRef);
-    CGDataProviderRelease(dataProviderRef);
-    UIImage *uiimg = [UIImage imageWithCGImage:img];
-    CGImageRelease(img);
-    return uiimg;
+    
+    if (img) {
+        UIImage *uiimg = [UIImage imageWithCGImage:img];
+        CGImageRelease(img);
+        return uiimg;
+    } else {
+        return nil;
+    }
 }
 
 @synthesize drawLock = _drawLock;
@@ -346,16 +362,18 @@ static void cs_channel_destroy(SpiceSession *s, SpiceChannel *channel, gpointer
 
 - (void)drawRegion:(CGRect)rect {
     NSInteger pixelSize = (_canvasFormat == SPICE_SURFACE_FMT_32_xRGB) ? 4 : 2;
-    // copy texture
+    // create draw region
     MTLRegion region = {
         { rect.origin.x-_visibleArea.origin.x, rect.origin.y-_visibleArea.origin.y, 0 }, // MTLOrigin
         { rect.size.width, rect.size.height, 1} // MTLSize
     };
     dispatch_semaphore_wait(_drawLock, DISPATCH_TIME_FOREVER);
-    [_texture replaceRegion:region
-                mipmapLevel:0
-                  withBytes:(const char *)_canvasData + (NSUInteger)(rect.origin.y*_canvasStride + rect.origin.x*pixelSize)
-                bytesPerRow:_canvasStride];
+    if (_canvasData != NULL) { // canvas may be destroyed by this time
+        [_texture replaceRegion:region
+                    mipmapLevel:0
+                      withBytes:(const char *)_canvasData + (NSUInteger)(rect.origin.y*_canvasStride + rect.origin.x*pixelSize)
+                    bytesPerRow:_canvasStride];
+    }
     dispatch_semaphore_signal(_drawLock);
 }