fix(Metal): improve shader stability

* use MTKView, which handles layer and scaling changes automatically
  between displays
This commit is contained in:
Stuart Carnie 2018-06-23 13:32:46 -07:00
parent ee8d82dcfe
commit eacd52f009
12 changed files with 268 additions and 142 deletions

View File

@ -12,7 +12,6 @@
#import "Context.h"
#import "PixelConverter.h"
@class ViewDescriptor;
@protocol View;
@interface Renderer : NSObject

View File

@ -113,9 +113,7 @@
{
MTLRenderPassDescriptor *rpd = [MTLRenderPassDescriptor new];
// Cornflower Blue #58BAF9
//rpd.colorAttachments[0].clearColor = MTLClearColorMake(0x58 / 255.0, 0xba / 255.0, 0xf9 / 255.0, 1.0);
rpd.colorAttachments[0].loadAction = MTLLoadActionLoad;
rpd.colorAttachments[0].loadAction = MTLLoadActionDontCare;
rpd.colorAttachments[0].storeAction = MTLStoreActionStore;
_t_rpd = rpd;
}
@ -163,49 +161,60 @@
for (id<View> v in _views) {
if (!v.visible) continue;
if ([v respondsToSelector:@selector(prepareFrame:)]) {
[v prepareFrame:_context];
if ([v respondsToSelector:@selector(drawWithContext:)]) {
[v drawWithContext:_context];
}
}
id<CAMetalDrawable> drawable = _context.nextDrawable;
_t_rpd.colorAttachments[0].texture = drawable.texture;
id<MTLRenderCommandEncoder> rce = [cb renderCommandEncoderWithDescriptor:_t_rpd];
[rce setVertexBytes:&_uniforms length:sizeof(_uniforms) atIndex:BufferIndexUniforms];
BOOL pendingDraws = NO;
for (id<View> v in _views) {
if (!v.visible ||
![v respondsToSelector:@selector(drawWithEncoder:)]) {
continue;
if (v.visible && (v.drawState & ViewDrawStateEncoder) != 0) {
pendingDraws = YES;
break;
}
// set view state
if (v.format == RPixelFormatBGRX8Unorm) {
[rce setRenderPipelineState:_t_pipelineStateNoAlpha];
}
else {
[rce setRenderPipelineState:_t_pipelineState];
}
if (v.filter == RTextureFilterNearest) {
[rce setFragmentSamplerState:_samplerStateNearest atIndex:SamplerIndexDraw];
}
else {
[rce setFragmentSamplerState:_samplerStateLinear atIndex:SamplerIndexDraw];
}
[v drawWithEncoder:rce];
}
[rce endEncoding];
if (pendingDraws) {
id<CAMetalDrawable> drawable = _context.nextDrawable;
_t_rpd.colorAttachments[0].texture = drawable.texture;
id<MTLRenderCommandEncoder> rce = [cb renderCommandEncoderWithDescriptor:_t_rpd];
[rce setVertexBytes:&_uniforms length:sizeof(_uniforms) atIndex:BufferIndexUniforms];
for (id<View> v in _views) {
if (!v.visible ||
![v respondsToSelector:@selector(drawWithEncoder:)] ||
(v.drawState & ViewDrawStateEncoder) == 0) {
continue;
}
// set view state
if (v.format == RPixelFormatBGRX8Unorm || v.format == RPixelFormatB5G6R5Unorm) {
[rce setRenderPipelineState:_t_pipelineStateNoAlpha];
}
else {
[rce setRenderPipelineState:_t_pipelineState];
}
if (v.filter == RTextureFilterNearest) {
[rce setFragmentSamplerState:_samplerStateNearest atIndex:SamplerIndexDraw];
}
else {
[rce setFragmentSamplerState:_samplerStateLinear atIndex:SamplerIndexDraw];
}
[v drawWithEncoder:rce];
}
[rce endEncoding];
}
__block dispatch_semaphore_t inflight = _inflightSemaphore;
[cb addCompletedHandler:^(id<MTLCommandBuffer> _) {
dispatch_semaphore_signal(inflight);
}];
[cb presentDrawable:drawable];
[cb presentDrawable:_context.nextDrawable];
[_context end];
}

View File

@ -11,33 +11,34 @@
#import <Foundation/Foundation.h>
// TODO(sgc): implement triple buffering
/*! @brief maximum inflight frames */
#define MAX_INFLIGHT 3
#define MAX_INFLIGHT 1
#pragma mark - Pixel Formats
typedef NS_ENUM(NSUInteger, RPixelFormat) {
RPixelFormatInvalid,
/* 16-bit formats */
RPixelFormatBGRA4Unorm,
RPixelFormatB5G6R5Unorm,
RPixelFormatBGRA8Unorm,
RPixelFormatBGRX8Unorm,
RPixelFormatCount,
RPixelFormatInvalid,
/* 16-bit formats */
RPixelFormatBGRA4Unorm,
RPixelFormatB5G6R5Unorm,
RPixelFormatBGRA8Unorm,
RPixelFormatBGRX8Unorm, // RetroArch XRGB
RPixelFormatCount,
};
extern NSUInteger RPixelFormatToBPP(RPixelFormat format);
extern NSString *NSStringFromRPixelFormat(RPixelFormat format);
typedef NS_ENUM(NSUInteger, RTextureFilter) {
RTextureFilterNearest,
RTextureFilterLinear,
RTextureFilterCount,
RTextureFilterNearest,
RTextureFilterLinear,
RTextureFilterCount,
};
#endif /* RendererCommon_h */

View File

@ -13,11 +13,12 @@
@property (readwrite) BOOL visible;
@property (readwrite) CGRect frame;
@property (readwrite) CGSize size;
@property (readonly) ViewDrawState drawState;
- (instancetype)initWithDescriptor:(ViewDescriptor *)td renderer:(Renderer *)renderer;
- (void)prepareFrame:(Context *)ctx;
- (void)updateFrame:(void const *)src pitch:(NSUInteger)pitch;
- (void)drawWithContext:(Context *)ctx;
- (void)drawWithEncoder:(id<MTLRenderCommandEncoder>)rce;
- (void)updateFrame:(void const *)src pitch:(NSUInteger)pitch;
@end

View File

@ -35,6 +35,11 @@
_filter = d.filter;
_context = r.context;
_visible = YES;
if (_format == RPixelFormatBGRA8Unorm || _format == RPixelFormatBGRX8Unorm) {
_drawState = ViewDrawStateEncoder;
} else {
_drawState = ViewDrawStateAll;
}
self.size = d.size;
self.frame = CGRectMake(0, 0, 1, 1);
}
@ -113,7 +118,7 @@
_pixelsDirty = NO;
}
- (void)prepareFrame:(Context *)ctx {
- (void)drawWithContext:(Context *)ctx {
[self _convertFormat];
}

View File

@ -10,6 +10,15 @@
#import <Foundation/Foundation.h>
#import <Metal/Metal.h>
typedef NS_ENUM(NSInteger, ViewDrawState)
{
ViewDrawStateNone = 0x00,
ViewDrawStateContext = 0x01,
ViewDrawStateEncoder = 0x02,
ViewDrawStateAll = 0x03,
};
@protocol View<NSObject>
@property (readonly) RPixelFormat format;
@ -17,9 +26,10 @@
@property (readwrite) BOOL visible;
@property (readwrite) CGRect frame;
@property (readwrite) CGSize size;
@property (readonly) ViewDrawState drawState;
@optional
- (void)prepareFrame:(Context *)ctx;
- (void)drawWithContext:(Context *)ctx;
- (void)drawWithEncoder:(id<MTLRenderCommandEncoder>)rce;
@end

View File

@ -9,6 +9,7 @@
#define METAL_COMMON_H__
#import <Metal/Metal.h>
#import <MetalKit/MetalKit.h>
#import "metal/metal_common.h"
#include <retro_common_api.h>
@ -20,6 +21,9 @@
RETRO_BEGIN_DECLS
extern MTLPixelFormat glslang_format_to_metal(glslang_format fmt);
extern MTLPixelFormat SelectOptimalPixelFormat(MTLPixelFormat fmt);
#pragma mark - Classes
@interface FrameView : NSObject<View>
@ -29,6 +33,7 @@ RETRO_BEGIN_DECLS
@property (readwrite) BOOL visible;
@property (readwrite) CGRect frame;
@property (readwrite) CGSize size;
@property (readonly) ViewDrawState drawState;
@property (readonly) struct video_shader* shader;
@property (readwrite) uint64_t frameCount;
@ -53,7 +58,7 @@ RETRO_BEGIN_DECLS
filter:(RTextureFilter)filter;
@end
@interface MetalDriver : NSObject<PlatformDelegate>
@interface MetalDriver : NSObject<MTKViewDelegate>
@property (readonly) video_viewport_t* viewport;
@property (readwrite) bool keepAspect;
@ -71,11 +76,6 @@ RETRO_BEGIN_DECLS
/*! @brief setNeedsResize triggers a display resize */
- (void)setNeedsResize;
- (void)viewDidUpdateFrame:(NSRect)rect;
#pragma mark - Menu APIs
@end
RETRO_END_DECLS

View File

@ -32,7 +32,7 @@
@property (readwrite) video_viewport_t *viewport;
- (instancetype)initWithDescriptor:(ViewDescriptor *)td renderer:(Renderer *)renderer;
- (void)prepareFrame:(Context *)ctx;
- (void)drawWithContext:(Context *)ctx;
- (void)drawWithEncoder:(id<MTLRenderCommandEncoder>)rce;
@end
@ -72,32 +72,19 @@
}
}
#pragma mark - swap chain
- (void)viewDidUpdateFrame:(NSRect)rect
{
RARCH_LOG("[MetalDriver] viewDidUpdateFrame %s\n", NSStringFromRect(rect).UTF8String);
_viewport->full_width = (unsigned int)rect.size.width;
_viewport->full_height = (unsigned int)rect.size.height;
video_driver_set_size(&_viewport->full_width, &_viewport->full_height);
resize_chain = YES;
}
#pragma mark - video
- (void)setVideo:(const video_info_t *)video
{
_video = *video;
_viewport->full_width = _video.width;
_viewport->full_height = _video.height;
if (!_renderer) {
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
_device = device;
NSView *view = (NSView *)apple_platform.renderView;
MetalView *view = (MetalView *)apple_platform.renderView;
view.device = device;
CAMetalLayer *layer = (CAMetalLayer *)view.layer;
layer.device = device;
//layer.device = device;
_renderer = [[Renderer alloc] initWithDevice:device layer:layer];
_menu.renderer = _renderer;
}
@ -119,11 +106,6 @@
- (void)beginFrame
{
if (resize_chain) {
[_renderer drawableSizeWillChange:CGSizeMake(_viewport->full_width, _viewport->full_height)];
resize_chain = NO;
}
video_driver_update_viewport(_viewport, NO, _keepAspect);
[_renderer beginFrame];
@ -139,6 +121,21 @@
// TODO(sgc): resize all drawables
}
#pragma mark - MTKViewDelegate
- (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size {
RARCH_LOG("[MetalDriver] drawableSizeWillChange: %s\n", NSStringFromSize(size).UTF8String);
_viewport->full_width = (unsigned int)size.width;
_viewport->full_height = (unsigned int)size.height;
video_driver_set_size(&_viewport->full_width, &_viewport->full_height);
[_renderer drawableSizeWillChange:size];
video_driver_update_viewport(_viewport, NO, _keepAspect);
}
- (void)drawInMTKView:(MTKView *)view {
}
extern inline matrix_float4x4 matrix_proj_ortho1(float left, float right, float top, float bottom)
{
float near = 0;
@ -292,12 +289,18 @@ typedef struct ALIGN(16)
_format = d.format;
_bpp = RPixelFormatToBPP(_format);
_filter = d.filter;
if (_format == RPixelFormatBGRA8Unorm || _format == RPixelFormatBGRX8Unorm) {
_drawState = ViewDrawStateEncoder;
} else {
_drawState = ViewDrawStateAll;
}
_visible = YES;
_engine.mvp = matrix_proj_ortho1(0, 1, 0, 1);
[self _initSamplers];
self.size = d.size;
self.frame = CGRectMake(0, 0, 1, 1);
resize_render_targets = YES;
}
return self;
}
@ -425,7 +428,6 @@ typedef struct ALIGN(16)
if (init_history)
[self _initHistory];
else {
// TODO(sgc): change to ring buffer?
int k;
/* todo: what about frame-duping ?
* maybe clone d3d10_texture_t with AddRef */
@ -546,7 +548,7 @@ static vertex_t vertex_bytes[] = {
}
}
- (void)prepareFrame:(Context *)ctx
- (void)drawWithContext:(Context *)ctx
{
_texture = _engine.frame.texture[0].view;
[self _convertFormat];
@ -567,15 +569,15 @@ static vertex_t vertex_bytes[] = {
MTLRenderPassDescriptor *rpd = [MTLRenderPassDescriptor new];
rpd.colorAttachments[0].clearColor = MTLClearColorMake(0, 0, 0, 1.0);
rpd.colorAttachments[0].loadAction = MTLLoadActionDontCare;
rpd.colorAttachments[0].loadAction = MTLLoadActionClear;
rpd.colorAttachments[0].storeAction = MTLStoreActionStore;
BOOL firstPass = YES;
for (unsigned i = 0; i < _shader->passes; i++) {
BOOL lastPass = i == _shader->passes - 1;
BOOL backBuffer = (_engine.pass[i].rt.view == nil);
if (lastPass) {
if (backBuffer) {
rpd.colorAttachments[0].texture = _context.nextDrawable.texture;
}
else {
@ -630,7 +632,7 @@ static vertex_t vertex_bytes[] = {
texture_sem++;
}
if (lastPass) {
if (backBuffer) {
[rce setViewport:_engine.frame.viewport];
}
else {
@ -645,7 +647,11 @@ static vertex_t vertex_bytes[] = {
[rce endEncoding];
_texture = _engine.pass[i].rt.view;
}
_texture = nil;
if (_texture == nil) {
_drawState = ViewDrawStateContext;
} else {
_drawState = ViewDrawStateAll;
}
}
- (void)_updateRenderTargets
@ -712,15 +718,17 @@ static vertex_t vertex_bytes[] = {
}
RARCH_LOG("[Metal]: Updating framebuffer size %u x %u.\n", width, height);
if (i != (_shader->passes - 1)) {
MTLPixelFormat fmt = SelectOptimalPixelFormat(glslang_format_to_metal(_engine.pass[i].semantics.format));
if ((i != (_shader->passes - 1)) ||
(width != _viewport->width) || (height != _viewport->height) ||
fmt != MTLPixelFormatBGRA8Unorm)
{
_engine.pass[i].viewport.width = width;
_engine.pass[i].viewport.height = height;
_engine.pass[i].viewport.znear = 0.0;
_engine.pass[i].viewport.zfar = 1.0;
MTLTextureDescriptor *td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
MTLTextureDescriptor *td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:fmt
width:width
height:height
mipmapped:false];
@ -823,8 +831,16 @@ static vertex_t vertex_bytes[] = {
if (!slang_process(shader, i, RARCH_SHADER_METAL, 20000, &semantics_map, &_engine.pass[i].semantics))
return NO;
#ifdef DEBUG
bool save_msl = true;
#else
bool save_msl = false;
#endif
NSString *vs_src = [NSString stringWithUTF8String:shader->pass[i].source.string.vertex];
NSString *fs_src = [NSString stringWithUTF8String:shader->pass[i].source.string.fragment];
// vertex descriptor
@try {
// vertex descriptor
MTLVertexDescriptor *vd = [MTLVertexDescriptor new];
vd.attributes[0].offset = offsetof(vertex_t, pos);
vd.attributes[0].format = MTLVertexFormatFloat4;
@ -839,8 +855,11 @@ static vertex_t vertex_bytes[] = {
psd.label = [NSString stringWithFormat:@"pass %d", i];
MTLRenderPipelineColorAttachmentDescriptor *ca = psd.colorAttachments[0];
ca.pixelFormat = MTLPixelFormatBGRA8Unorm;
ca.blendingEnabled = YES;
ca.pixelFormat = SelectOptimalPixelFormat(glslang_format_to_metal(_engine.pass[i].semantics.format));
// TODO(sgc): confirm we never need blending for render passes
ca.blendingEnabled = NO;
ca.sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha;
ca.sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
ca.destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
@ -848,19 +867,18 @@ static vertex_t vertex_bytes[] = {
psd.sampleCount = 1;
psd.vertexDescriptor = vd;
NSString *vs_src = [NSString stringWithUTF8String:shader->pass[i].source.string.vertex];
NSLog(@"vertex function:\n%@", vs_src);
NSString *fs_src = [NSString stringWithUTF8String:shader->pass[i].source.string.fragment];
NSLog(@"fragment function:\n%@", fs_src);
NSError *err;
id<MTLLibrary> lib = [_context.device newLibraryWithSource:vs_src options:nil error:&err];
if (err != nil) {
if (lib == nil) {
save_msl = true;
RARCH_ERR("Metal]: unable to compile vertex shader: %s\n", err.localizedDescription.UTF8String);
return NO;
}
#if DEBUG
RARCH_WARN("[Metal]: warnings compiling vertex shader: %s\n", err.localizedDescription.UTF8String);
#endif
}
psd.vertexFunction = [lib newFunctionWithName:@"main0"];
@ -868,16 +886,20 @@ static vertex_t vertex_bytes[] = {
lib = [_context.device newLibraryWithSource:fs_src options:nil error:&err];
if (err != nil) {
if (lib == nil) {
save_msl = true;
RARCH_ERR("Metal]: unable to compile fragment shader: %s\n", err.localizedDescription.UTF8String);
return NO;
}
#if DEBUG
RARCH_WARN("[Metal]: warnings compiling fragment shader: %s\n", err.localizedDescription.UTF8String);
#endif
}
psd.fragmentFunction = [lib newFunctionWithName:@"main0"];
STRUCT_ASSIGN(_engine.pass[i]._state,
[_context.device newRenderPipelineStateWithDescriptor:psd error:&err]);
if (err != nil) {
save_msl = true;
RARCH_ERR("error creating pipeline state: %s", err.localizedDescription.UTF8String);
return NO;
}
@ -892,6 +914,29 @@ static vertex_t vertex_bytes[] = {
STRUCT_ASSIGN(_engine.pass[i].buffers[j], buf);
}
} @finally {
if (save_msl) {
RARCH_LOG("[Metal]: saving metal shader files\n");
NSError *err = nil;
NSString *basePath = [[NSString stringWithUTF8String:shader->pass[i].source.path] stringByDeletingPathExtension];
[vs_src writeToFile:[basePath stringByAppendingPathExtension:@"vs.metal"]
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:&err];
if (err != nil) {
RARCH_ERR("[Metal]: unable to save vertex shader source: %s\n", err.localizedDescription.UTF8String);
}
err = nil;
[fs_src writeToFile:[basePath stringByAppendingPathExtension:@"fs.metal"]
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:&err];
if (err != nil) {
RARCH_ERR("[Metal]: unable to save fragment shader source: %s\n", err.localizedDescription.UTF8String);
}
}
free(shader->pass[i].source.string.vertex);
free(shader->pass[i].source.string.fragment);
@ -945,3 +990,67 @@ static vertex_t vertex_bytes[] = {
}
@end
MTLPixelFormat glslang_format_to_metal(glslang_format fmt)
{
#undef FMT2
#define FMT2(x,y) case SLANG_FORMAT_##x: return MTLPixelFormat##y
switch (fmt)
{
FMT2(R8_UNORM, R8Unorm);
FMT2(R8_SINT, R8Sint);
FMT2(R8_UINT, R8Uint);
FMT2(R8G8_UNORM, RG8Unorm);
FMT2(R8G8_SINT, RG8Sint);
FMT2(R8G8_UINT, RG8Uint);
FMT2(R8G8B8A8_UNORM, RGBA8Unorm);
FMT2(R8G8B8A8_SINT, RGBA8Sint);
FMT2(R8G8B8A8_UINT, RGBA8Uint);
FMT2(R8G8B8A8_SRGB, RGBA8Unorm_sRGB);
FMT2(A2B10G10R10_UNORM_PACK32, RGB10A2Unorm);
FMT2(A2B10G10R10_UINT_PACK32, RGB10A2Uint);
FMT2(R16_UINT, R16Uint);
FMT2(R16_SINT, R16Sint);
FMT2(R16_SFLOAT, R16Float);
FMT2(R16G16_UINT, RG16Uint);
FMT2(R16G16_SINT, RG16Sint);
FMT2(R16G16_SFLOAT, RG16Float);
FMT2(R16G16B16A16_UINT, RGBA16Uint);
FMT2(R16G16B16A16_SINT, RGBA16Sint);
FMT2(R16G16B16A16_SFLOAT, RGBA16Float);
FMT2(R32_UINT, R32Uint);
FMT2(R32_SINT, R32Sint);
FMT2(R32_SFLOAT, R32Float);
FMT2(R32G32_UINT, RG32Uint);
FMT2(R32G32_SINT, RG32Sint);
FMT2(R32G32_SFLOAT, RG32Float);
FMT2(R32G32B32A32_UINT, RGBA32Uint);
FMT2(R32G32B32A32_SINT, RGBA32Sint);
FMT2(R32G32B32A32_SFLOAT, RGBA32Float);
case SLANG_FORMAT_UNKNOWN:
default:
break;
}
#undef FMT2
return MTLPixelFormatInvalid;
}
MTLPixelFormat SelectOptimalPixelFormat(MTLPixelFormat fmt)
{
switch (fmt)
{
case MTLPixelFormatRGBA8Unorm:
return MTLPixelFormatBGRA8Unorm;
case MTLPixelFormatRGBA8Unorm_sRGB:
return MTLPixelFormatBGRA8Unorm_sRGB;
default:
return fmt;
}
}

View File

@ -53,13 +53,14 @@ static void *metal_init(const video_info_t *video,
gfx_ctx_mode_t mode;
[apple_platform setViewType:APPLE_VIEW_TYPE_METAL];
MetalDriver *md = [MetalDriver new];
if (md == nil) {
return NULL;
}
MetalView *view = (MetalView *)apple_platform.renderView;
view.delegate = md;
apple_platform.delegate = md;
md.keepAspect = video->force_aspect;
RARCH_LOG("[Metal]: Detecting screen resolution %ux%u.\n", video->width, video->height);
@ -67,8 +68,8 @@ static void *metal_init(const video_info_t *video,
mode.height = video->height;
mode.fullscreen = video->fullscreen;
[apple_platform setVideoMode:mode];
[md setVideo:video];
[apple_platform setVideoMode:mode];
*input = NULL;
*input_data = NULL;

View File

@ -36,22 +36,16 @@ typedef enum apple_view_type {
APPLE_VIEW_TYPE_METAL,
} apple_view_type_t;
@protocol PlatformDelegate
#ifdef HAVE_METAL
@optional
- (void)viewDidUpdateFrame:(NSRect)rect;
#endif
#import <MetalKit/MetalKit.h>
@interface MetalView : MTKView
@end
#endif
@protocol ApplePlatform
@property (readwrite,retain) id<PlatformDelegate> delegate;
/*!
@brief viewHandle returns an appropriate handle for the current view type
*/
@property (readonly) id viewHandle;
/*! @brief renderView returns the current render view based on the viewType */
@property (readonly) id renderView;

View File

@ -19,9 +19,6 @@
#include "cocoa_common.h"
#ifdef HAVE_COCOA
#include "../ui_cocoa.h"
#ifdef HAVE_VULKAN
#import <QuartzCore/CAMetalLayer.h>
#endif
#endif
#include <retro_assert.h>
@ -46,6 +43,21 @@
#include "../../../location/location_driver.h"
#include "../../../camera/camera_driver.h"
#ifdef HAVE_METAL
@implementation MetalView
- (void)keyDown:(NSEvent*)theEvent
{
}
/* Stop the annoying sound when pressing a key. */
- (BOOL)acceptsFirstResponder
{
return YES;
}
@end
#endif
static CocoaView* g_instance;
#if defined(HAVE_COCOA)
@ -96,15 +108,13 @@ void *glkitview_init(void);
}
#if defined(HAVE_COCOA)
- (BOOL)layer:(CALayer *)layer shouldInheritContentsScale:(CGFloat)newScale fromWindow:(NSWindow *)window {
return YES;
}
- (void)setFrame:(NSRect)frameRect
{
[super setFrame:frameRect];
if (apple_platform.delegate != nil)
{
[apple_platform.delegate viewDidUpdateFrame:frameRect];
}
cocoagl_gfx_ctx_update();
}

View File

@ -53,7 +53,6 @@ id<ApplePlatform> apple_platform;
NSWindow* _window;
apple_view_type_t _vt;
NSView* _renderView;
id<PlatformDelegate> _delegate;
}
@property (nonatomic, retain) NSWindow IBOutlet* window;
@ -259,9 +258,9 @@ static char** waiting_argv;
case APPLE_VIEW_TYPE_METAL:
#if defined(HAVE_METAL) || defined(HAVE_VULKAN)
{
NSView *v = [CocoaView get];
v.wantsLayer = YES;
v.layer = CAMetalLayer.layer;
MetalView *v = [MetalView new];
v.paused = YES;
v.enableSetNeedsDisplay = NO;
_renderView = v;
}
#endif
@ -280,7 +279,7 @@ static char** waiting_argv;
_renderView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
_renderView.frame = self.window.contentView.bounds;
[self.window.contentView addSubview:_renderView];
[self.window makeFirstResponder:_renderView];
}
@ -293,18 +292,6 @@ static char** waiting_argv;
return _renderView;
}
- (id)delegate {
return _delegate;
}
- (void)setDelegate:(id<PlatformDelegate>)delegate {
_delegate = delegate;
}
- (id)viewHandle {
return nil;
}
- (bool)hasFocus {
return [NSApp isActive];
}