Search code examples
metal

How to get a snapshot of current drawable with metal on mac?


I found a similar post here and here. I tried the following codes, it works fine in iOS 12.1.4 but empty on macOS Mojave version 10.14

    id<CAMetalDrawable> lastDrawable = view.currentDrawable;
    [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> commandBuffer) {
        id<MTLTexture> drawableTexture = lastDrawable.texture;
        int width = (int)drawableTexture.width;
        int height = (int)drawableTexture.height;
        int len = width * height * 4;
        uint8_t* image = (uint8_t*)malloc(len);
        [drawableTexture getBytes:image bytesPerRow:width*4 fromRegion:MTLRegionMake2D(0, 0, width, height) mipmapLevel:0];

        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGContextRef bitmapContext = CGBitmapContextCreate(
                                                           image,
                                                           width,
                                                           height,
                                                           8, // bitsPerComponent
                                                           4*width, // bytesPerRow
                                                           colorSpace,
                                                           kCGImageAlphaNoneSkipLast);

        CFRelease(colorSpace);

        CGImageRef cgImage = CGBitmapContextCreateImage(bitmapContext);
        CFRelease(cgImage);
        CFRelease(bitmapContext);
        free(image);
    }];

Do I need some additional processes to get a correct snapshot of the current screen on mac?


Solution

  • The storage mode of the drawable's texture is managed. You need to use a blit command encoder to encode a -synchronize... command. Otherwise, the data isn't guaranteed to be available to the CPU.