From 0e295716b9908c8a9ac1e89e30b735e008e6f55c Mon Sep 17 00:00:00 2001 From: Stuart Carnie Date: Thu, 29 Nov 2018 22:04:43 -0700 Subject: [PATCH] feat(metal): Add native rotation support for Metal driver * fix crash when frame or frame size is 0 --- gfx/common/metal/Context.h | 1 + gfx/common/metal/Context.m | 34 +++++++++++++- gfx/common/metal/RendererCommon.h | 1 + gfx/common/metal/RendererCommon.m | 14 ++++++ gfx/common/metal_common.h | 2 + gfx/common/metal_common.m | 44 +++++++++++-------- gfx/drivers/metal.m | 18 +++++--- .../RetroArch_Metal.xcodeproj/project.pbxproj | 32 +++++++++++++- 8 files changed, 118 insertions(+), 28 deletions(-) diff --git a/gfx/common/metal/Context.h b/gfx/common/metal/Context.h index 5068df92a2..2897367664 100644 --- a/gfx/common/metal/Context.h +++ b/gfx/common/metal/Context.h @@ -76,6 +76,7 @@ typedef struct /*! @brief end commits the command buffer */ - (void)end; +- (void)setRotation:(unsigned)rotation; - (bool)readBackBuffer:(uint8_t *)buffer; @end diff --git a/gfx/common/metal/Context.m b/gfx/common/metal/Context.m index 69d1c059f6..34fc099afc 100644 --- a/gfx/common/metal/Context.m +++ b/gfx/common/metal/Context.m @@ -53,10 +53,16 @@ id _states[GFX_MAX_SHADERS][2]; id _clearState; - Uniforms _uniforms; bool _captureEnabled; id _backBuffer; + + unsigned _rotation; + matrix_float4x4 _mvp_no_rot; + matrix_float4x4 _mvp; + + Uniforms _uniforms; + Uniforms _uniformsNoRotate; } - (instancetype)initWithDevice:(id)d @@ -75,6 +81,11 @@ _commandQueue = [_device newCommandQueue]; _clearColor = MTLClearColorMake(0, 0, 0, 1); _uniforms.projectionMatrix = matrix_proj_ortho(0, 1, 0, 1); + + _rotation = 0; + [self setRotation:0]; + _mvp_no_rot = matrix_proj_ortho(0, 1, 0, 1); + _mvp = matrix_proj_ortho(0, 1, 0, 1); { MTLSamplerDescriptor *sd = [MTLSamplerDescriptor new]; @@ -130,6 +141,27 @@ return &_uniforms; } +- (void)setRotation:(unsigned)rotation +{ + _rotation = 270 * rotation; + + /* Calculate projection. */ + _mvp_no_rot = matrix_proj_ortho(0, 1, 0, 1); + + bool allow_rotate = true; + if (!allow_rotate) + { + _mvp = _mvp_no_rot; + return; + } + + matrix_float4x4 rot = matrix_rotate_z((float)(M_PI * _rotation / 180.0f)); + _mvp = simd_mul(rot, _mvp_no_rot); + + _uniforms.projectionMatrix = _mvp; + _uniformsNoRotate.projectionMatrix = _mvp_no_rot; +} + - (void)setDisplaySyncEnabled:(bool)displaySyncEnabled { #if TARGET_OS_OSX diff --git a/gfx/common/metal/RendererCommon.h b/gfx/common/metal/RendererCommon.h index 977cf7b607..f0835f271e 100644 --- a/gfx/common/metal/RendererCommon.h +++ b/gfx/common/metal/RendererCommon.h @@ -55,6 +55,7 @@ typedef NS_ENUM(NSUInteger, RTextureFilter) }; extern matrix_float4x4 matrix_proj_ortho(float left, float right, float top, float bottom); +extern matrix_float4x4 matrix_rotate_z(float rot); extern matrix_float4x4 make_matrix_float4x4(const float *v); #endif /* RendererCommon_h */ diff --git a/gfx/common/metal/RendererCommon.m b/gfx/common/metal/RendererCommon.m index c3be58dc86..95ff5c889c 100644 --- a/gfx/common/metal/RendererCommon.m +++ b/gfx/common/metal/RendererCommon.m @@ -86,3 +86,17 @@ matrix_float4x4 matrix_proj_ortho(float left, float right, float top, float bott matrix_float4x4 mat = {P, Q, R, S}; return mat; } + +matrix_float4x4 matrix_rotate_z(float rot) +{ + float cz, sz; + __sincosf(rot, &sz, &cz); + + simd_float4 P = simd_make_float4(cz, -sz, 0, 0); + simd_float4 Q = simd_make_float4(sz, cz, 0, 0); + simd_float4 R = simd_make_float4( 0, 0, 1, 0); + simd_float4 S = simd_make_float4( 0, 0, 0, 1); + + matrix_float4x4 mat = {P, Q, R, S}; + return mat; +} diff --git a/gfx/common/metal_common.h b/gfx/common/metal_common.h index 66b7f08b92..4fbefa25ac 100644 --- a/gfx/common/metal_common.h +++ b/gfx/common/metal_common.h @@ -96,6 +96,8 @@ extern MTLPixelFormat SelectOptimalPixelFormat(MTLPixelFormat fmt); /*! @brief setNeedsResize triggers a display resize */ - (void)setNeedsResize; +- (void)setViewportWidth:(unsigned)width height:(unsigned)height forceFull:(BOOL)forceFull allowRotate:(BOOL)allowRotate; +- (void)setRotation:(unsigned)rotation; @end diff --git a/gfx/common/metal_common.m b/gfx/common/metal_common.m index 2c2129d911..d2afec6184 100644 --- a/gfx/common/metal_common.m +++ b/gfx/common/metal_common.m @@ -216,21 +216,19 @@ return YES; } -- (void)_updateUniforms +- (void)setViewportWidth:(unsigned)width height:(unsigned)height forceFull:(BOOL)forceFull allowRotate:(BOOL)allowRotate { - _uniforms.projectionMatrix = matrix_proj_ortho(0, 1, 0, 1); -} - -- (void)_updateViewport:(CGSize)size -{ - RARCH_LOG("[Metal]: _updateViewport size %.0fx%.0f\n", size.width, size.height); +#if 0 + RARCH_LOG("[Metal]: setViewportWidth size %dx%d\n", width, height); +#endif - _viewport->full_width = (unsigned int)size.width; - _viewport->full_height = (unsigned int)size.height; + _viewport->full_width = width; + _viewport->full_height = height; video_driver_set_size(&_viewport->full_width, &_viewport->full_height); - _layer.drawableSize = size; - video_driver_update_viewport(_viewport, NO, _keepAspect); + _layer.drawableSize = CGSizeMake(width, height); + video_driver_update_viewport(_viewport, forceFull, _keepAspect); + // update matrix _context.viewport = _viewport; _viewportMVP.outputSize = simd_make_float2(_viewport->full_width, _viewport->full_height); @@ -256,8 +254,10 @@ [self _beginFrame]; _frameView.frameCount = frameCount; - _frameView.size = CGSizeMake(width, height); - [_frameView updateFrame:data pitch:pitch]; + if (data && width && height) { + _frameView.size = CGSizeMake(width, height); + [_frameView updateFrame:data pitch:pitch]; + } [self _drawViews:video_info]; @@ -277,7 +277,7 @@ id rce = _context.rce; [rce pushDebugGroup:@"overlay"]; [rce setRenderPipelineState:[_context getStockShader:VIDEO_SHADER_STOCK_BLEND blend:YES]]; - [rce setVertexBytes:&_uniforms length:sizeof(_uniforms) atIndex:BufferIndexUniforms]; + [rce setVertexBytes:_context.uniforms length:sizeof(*_context.uniforms) atIndex:BufferIndexUniforms]; [rce setFragmentSamplerState:_samplerStateLinear atIndex:SamplerIndexDraw]; [_overlay drawWithEncoder:rce]; [rce popDebugGroup]; @@ -338,7 +338,6 @@ _context.viewport = _viewport; } [_context begin]; - [self _updateUniforms]; } - (void)_drawViews:(video_frame_info_t *)video_info @@ -351,7 +350,7 @@ if ((_frameView.drawState & ViewDrawStateEncoder) != 0) { - [rce setVertexBytes:&_uniforms length:sizeof(_uniforms) atIndex:BufferIndexUniforms]; + [rce setVertexBytes:_context.uniforms length:sizeof(*_context.uniforms) atIndex:BufferIndexUniforms]; [rce setRenderPipelineState:_t_pipelineStateNoAlpha]; if (_frameView.filter == RTextureFilterNearest) { @@ -410,6 +409,11 @@ // TODO(sgc): resize all drawables } +- (void)setRotation:(unsigned)rotation +{ + [_context setRotation:rotation]; +} + - (Uniforms *)viewportMVP { return &_viewportMVP; @@ -419,7 +423,7 @@ - (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size { - [self _updateViewport:size]; + [self setViewportWidth:(unsigned int)size.width height:(unsigned int)size.height forceFull:NO allowRotate:YES]; } - (void)drawInMTKView:(MTKView *)view @@ -897,7 +901,7 @@ typedef struct MTLALIGN(16) rce = [cb renderCommandEncoderWithDescriptor:rpd]; } -#if METAL_DEBUG +#if DEBUG && METAL_DEBUG rce.label = [NSString stringWithFormat:@"pass %d", i]; #endif @@ -1126,6 +1130,8 @@ typedef struct MTLALIGN(16) texture_t *source = &_engine.frame.texture[0]; for (unsigned i = 0; i < shader->passes; source = &_engine.pass[i++].rt) { + matrix_float4x4 *mvp = (i == shader->passes-1) ? &_context.uniforms->projectionMatrix : &_engine.mvp; + /* clang-format off */ semantics_map_t semantics_map = { { @@ -1154,7 +1160,7 @@ typedef struct MTLALIGN(16) &_engine.luts[0].size_data, sizeof(*_engine.luts)}, }, { - &_engine.mvp, /* MVP */ + mvp, /* MVP */ &_engine.pass[i].rt.size_data, /* OutputSize */ &_engine.frame.output_size, /* FinalViewportSize */ &_engine.pass[i].frame_count, /* FrameCount */ diff --git a/gfx/drivers/metal.m b/gfx/drivers/metal.m index 3496d035bf..29c792c9ab 100644 --- a/gfx/drivers/metal.m +++ b/gfx/drivers/metal.m @@ -151,16 +151,22 @@ static void metal_free(void *data) static void metal_set_viewport(void *data, unsigned viewport_width, unsigned viewport_height, bool force_full, bool allow_rotate) { -#if 0 - RARCH_LOG("[Metal]: set_viewport size: %dx%d full: %s rotate: %s\n", - viewport_width, viewport_height, - force_full ? "YES" : "NO", - allow_rotate ? "YES" : "NO"); -#endif + MetalDriver *md = (__bridge MetalDriver *)data; + if (md == nil) { + return; + } + + [md setViewportWidth:viewport_width height:viewport_height forceFull:force_full allowRotate:allow_rotate]; } static void metal_set_rotation(void *data, unsigned rotation) { + MetalDriver *md = (__bridge MetalDriver *)data; + if (md == nil) { + return; + } + + [md setRotation:rotation]; } static void metal_viewport_info(void *data, struct video_viewport *vp) diff --git a/pkg/apple/RetroArch_Metal.xcodeproj/project.pbxproj b/pkg/apple/RetroArch_Metal.xcodeproj/project.pbxproj index a97c52c3f8..5ca7fea33a 100644 --- a/pkg/apple/RetroArch_Metal.xcodeproj/project.pbxproj +++ b/pkg/apple/RetroArch_Metal.xcodeproj/project.pbxproj @@ -88,6 +88,17 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 05132C6621A74D7A00379846 /* ozone_texture.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ozone_texture.c; sourceTree = ""; }; + 05132C6721A74D7B00379846 /* ozone_theme.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ozone_theme.h; sourceTree = ""; }; + 05132C6821A74D7B00379846 /* ozone.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ozone.h; sourceTree = ""; }; + 05132C6921A74D7B00379846 /* ozone_entries.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ozone_entries.c; sourceTree = ""; }; + 05132C6A21A74D7B00379846 /* ozone.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ozone.c; sourceTree = ""; }; + 05132C6B21A74D7B00379846 /* ozone_theme.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ozone_theme.c; sourceTree = ""; }; + 05132C6C21A74D7B00379846 /* ozone_sidebar.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ozone_sidebar.c; sourceTree = ""; }; + 05132C6D21A74D7B00379846 /* ozone_sidebar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ozone_sidebar.h; sourceTree = ""; }; + 05132C6E21A74D7B00379846 /* ozone_display.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ozone_display.c; sourceTree = ""; }; + 05132C6F21A74D7B00379846 /* ozone_texture.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ozone_texture.h; sourceTree = ""; }; + 05132C7021A74D7B00379846 /* ozone_display.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ozone_display.h; sourceTree = ""; }; 05269A6120ABF20500C29F1E /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; }; 05366512213F8BE5007E7EA0 /* thumbnailpackdownload.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = thumbnailpackdownload.cpp; sourceTree = ""; }; 05366513213F8BE5007E7EA0 /* ui_qt_application.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ui_qt_application.cpp; sourceTree = ""; }; @@ -514,7 +525,6 @@ 05D7753320A5678300646447 /* griffin_cpp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = griffin_cpp.cpp; path = ../../griffin/griffin_cpp.cpp; sourceTree = ""; }; 05D7753420A5678400646447 /* griffin_glslang.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = griffin_glslang.cpp; path = ../../griffin/griffin_glslang.cpp; sourceTree = ""; }; 05EFAFC22191D64200D27059 /* stripes.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = stripes.c; sourceTree = ""; }; - 05EFAFC32191D64200D27059 /* ozone.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ozone.c; sourceTree = ""; }; 05F2872F20F2BEEA00632D47 /* task_autodetect.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = task_autodetect.c; sourceTree = ""; }; 05F2873020F2BEEA00632D47 /* task_netplay_find_content.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = task_netplay_find_content.c; sourceTree = ""; }; 05F2873120F2BEEA00632D47 /* task_netplay_nat_traversal.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = task_netplay_nat_traversal.c; sourceTree = ""; }; @@ -610,6 +620,24 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 05132C6521A74D5100379846 /* ozone */ = { + isa = PBXGroup; + children = ( + 05132C6E21A74D7B00379846 /* ozone_display.c */, + 05132C7021A74D7B00379846 /* ozone_display.h */, + 05132C6921A74D7B00379846 /* ozone_entries.c */, + 05132C6C21A74D7B00379846 /* ozone_sidebar.c */, + 05132C6D21A74D7B00379846 /* ozone_sidebar.h */, + 05132C6621A74D7A00379846 /* ozone_texture.c */, + 05132C6F21A74D7B00379846 /* ozone_texture.h */, + 05132C6B21A74D7B00379846 /* ozone_theme.c */, + 05132C6721A74D7B00379846 /* ozone_theme.h */, + 05132C6A21A74D7B00379846 /* ozone.c */, + 05132C6821A74D7B00379846 /* ozone.h */, + ); + path = ozone; + sourceTree = ""; + }; 05366511213F8BE5007E7EA0 /* qt */ = { isa = PBXGroup; children = ( @@ -801,12 +829,12 @@ isa = PBXGroup; children = ( 05A8C53520DB72F000FF7857 /* nuklear */, + 05132C6521A74D5100379846 /* ozone */, 05A8C54020DB72F000FF7857 /* materialui.c */, 05A8C53420DB72F000FF7857 /* menu_generic.c */, 05A8C53320DB72F000FF7857 /* menu_generic.h */, 05A8C53D20DB72F000FF7857 /* nuklear.c */, 05A8C53E20DB72F000FF7857 /* null.c */, - 05EFAFC32191D64200D27059 /* ozone.c */, 05A8C53C20DB72F000FF7857 /* rgui.c */, 05EFAFC22191D64200D27059 /* stripes.c */, 05A8C53220DB72F000FF7857 /* xmb.c */,