在重绘之前调整MTKView的大小可以缩放旧内容

问题描述 投票:1回答:2

我正在使用MTKView绘制金属内容。配置如下:

    mtkView = MTKView(frame: self.view.frame, device: device)
    mtkView.colorPixelFormat = .bgra8Unorm
    mtkView.delegate=self
    mtkView.sampleCount=4
    mtkView.isPaused=true
    mtkView.enableSetNeedsDisplay=true

qazxsw poi被覆盖以触发重新显示。

每当视图调整大小时,它会在重绘所有内容之前缩放其旧内容。这给人一种抖动的感觉。

我尝试将MTKView图层的setFrameSize属性设置为非调整大小的值,但这完全弄乱了内容的比例和位置。似乎MTKView不希望我摆弄那个参数。

如何确保在调整大小期间始终正确地重新绘制内容?

macos core-animation metal
2个回答
1
投票

在我使用Metal和contentGravity时,我尝试了MTKViewpresentsWithTransaction的各种组合而没有成功。在实时调整大小期间,我仍然在正确呈现内容的帧之间偶尔会遇到拉伸内容的帧。

最后,我完全放弃了waitUntilScheduled并制作了我自己的NSView子类,它使用MTKView并且resize现在看起来很好(没有使用CAMetalLayerpresentsWithTransaction)。关键一点是我需要设置图层的waitUntilScheduled以在窗口调整大小期间每帧调用autoresizingMask方法。

这是头文件:

displayLayer

这是实施:

#import <Cocoa/Cocoa.h>

@interface MyMTLView : NSView<CALayerDelegate>    
@end

作为参考,我用MTKView的#import <QuartzCore/CAMetalLayer.h> #import <Metal/Metal.h> @implementation MyMTLView - (id)initWithFrame:(NSRect)frame { if (!(self = [super initWithFrame:frame])) { return self; } // We want to be backed by a CAMetalLayer. self.wantsLayer = YES; // We want to redraw the layer during live window resize. self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize; // Not strictly necessary, but in case something goes wrong with live window // resize, this layer placement makes it more obvious what's going wrong. self.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft; return self; } - (CALayer*)makeBackingLayer { CAMetalLayer* metalLayer = [CAMetalLayer layer]; metalLayer.device = MTLCreateSystemDefaultDevice(); metalLayer.delegate = self; // *Both* of these properties are crucial to getting displayLayer to be // called during live window resize. metalLayer.autoresizingMask = kCALayerHeightSizable | kCALayerWidthSizable; metalLayer.needsDisplayOnBoundsChange = YES; return metalLayer; } - (CAMetalLayer*)metalLayer { return (CAMetalLayer*)self.layer; } - (void)setFrameSize:(NSSize)newSize { [super setFrameSize:newSize]; self.metalLayer.drawableSize = newSize; } - (void)displayLayer:(CALayer*)layer { // Do drawing with Metal. } @end 方法完成所有的Metal绘图。


1
投票

我有同样的问题与视图调整大小的毛刺。您甚至可以在Apple开发者网站的HelloTriangle示例中重现它。然而,效果被最小化,因为三角形被绘制在屏幕的中间附近,并且它是最接近窗口边缘的内容,在拖动的角落的对面,这是最坏的。关于使用drawRectpresentsWithTransaction的开发人员注意事项也不适用于我。

我的解决方案是在waitUntilScheduled下面添加一个Metal层,并使该层足够大,很少需要调整大小。这样做的原因在于,与window.contentView.layer不同,window.contentView.layer自动调整视图大小(进而保持窗口大小),您可以明确控制子图层大小。这消除了闪烁。

© www.soinside.com 2019 - 2024. All rights reserved.