diff --git a/gfx/common/metal/Context.h b/gfx/common/metal/Context.h index d1ae25b9e7..79577dfd22 100644 --- a/gfx/common/metal/Context.h +++ b/gfx/common/metal/Context.h @@ -20,10 +20,18 @@ @property (readonly) id device; @property (readonly) id library; + +/*! @brief Returns the command buffer used for pre-render work, + * such as mip maps for applying filters + * */ +@property (readonly) id blitCommandBuffer; + /*! @brief Returns the command buffer for the current frame */ @property (readonly) id commandBuffer; @property (readonly) id nextDrawable; -@property (readonly) id renderTexture; + +/*! @brief Main render encoder to back buffer */ +@property (readonly) id rce; - (instancetype)initWithDevice:(id)d layer:(CAMetalLayer *)layer diff --git a/gfx/common/metal/Context.m b/gfx/common/metal/Context.m index f525617841..cc77a484b2 100644 --- a/gfx/common/metal/Context.m +++ b/gfx/common/metal/Context.m @@ -16,18 +16,21 @@ @end @interface Context() -@property (readonly) id blitCommandBuffer; - (bool)_initConversionFilters; @end @implementation Context { + dispatch_semaphore_t _inflightSemaphore; id _commandQueue; CAMetalLayer *_layer; id _drawable; id _samplers[TEXTURE_FILTER_MIPMAP_NEAREST + 1]; Filter *_filters[RPixelFormatCount]; // convert to bgra8888 + // main render pass state + id _rce; + id _blitCommandBuffer; } @@ -37,6 +40,7 @@ { if (self = [super init]) { + _inflightSemaphore = dispatch_semaphore_create(MAX_INFLIGHT); _device = d; _layer = layer; _library = l; @@ -63,10 +67,18 @@ if (![self _initConversionFilters]) return nil; + + if (![self _initMainState]) + return nil; } return self; } +- (bool)_initMainState +{ + return YES; +} + - (bool)_initConversionFilters { NSError *err = nil; @@ -158,18 +170,13 @@ return _drawable; } -- (id)renderTexture -{ - return self.nextDrawable.texture; -} - - (void)convertFormat:(RPixelFormat)fmt from:(id)src to:(id)dst { assert(dst.width * dst.height == src.length / RPixelFormatToBPP(fmt)); assert(fmt >= 0 && fmt < RPixelFormatCount); Filter *conv = _filters[fmt]; assert(conv != nil); - [conv apply:self.commandBuffer inBuf:src outTex:dst]; + [conv apply:self.blitCommandBuffer inBuf:src outTex:dst]; } - (id)blitCommandBuffer @@ -182,9 +189,22 @@ - (void)begin { assert(_commandBuffer == nil); + dispatch_semaphore_wait(_inflightSemaphore, DISPATCH_TIME_FOREVER); _commandBuffer = [_commandQueue commandBuffer]; } +- (id)rce +{ + assert(_commandBuffer != nil); + if (_rce == nil) + { + MTLRenderPassDescriptor *rpd = [MTLRenderPassDescriptor new]; + rpd.colorAttachments[0].texture = self.nextDrawable.texture; + _rce = [_commandBuffer renderCommandEncoderWithDescriptor:rpd]; + } + return _rce; +} + - (void)end { assert(self->_commandBuffer != nil); @@ -197,7 +217,20 @@ _blitCommandBuffer = nil; } + if (_rce) + { + [_rce endEncoding]; + _rce = nil; + } + + __block dispatch_semaphore_t inflight = _inflightSemaphore; + [_commandBuffer addCompletedHandler:^(id _) { + dispatch_semaphore_signal(inflight); + }]; + + [_commandBuffer presentDrawable:self.nextDrawable]; [_commandBuffer commit]; + _commandBuffer = nil; _drawable = nil; } diff --git a/gfx/common/metal/MenuDisplay.h b/gfx/common/metal/MenuDisplay.h index fb8bef3c62..ff5347e38f 100644 --- a/gfx/common/metal/MenuDisplay.h +++ b/gfx/common/metal/MenuDisplay.h @@ -14,6 +14,7 @@ @property (readwrite) MTLClearColor clearColor; - (instancetype)initWithDriver:(MetalDriver *)driver; +- (void)drawPipeline:(menu_display_ctx_draw_t *)draw video:(video_frame_info_t *)video; - (void)draw:(menu_display_ctx_draw_t *)draw video:(video_frame_info_t *)video; #pragma mark - static methods diff --git a/gfx/common/metal/MenuDisplay.m b/gfx/common/metal/MenuDisplay.m index 0510f655ce..7bc93f2a1e 100644 --- a/gfx/common/metal/MenuDisplay.m +++ b/gfx/common/metal/MenuDisplay.m @@ -166,6 +166,11 @@ static INLINE void write_quad4a(SpriteVertex *pv, } } +- (void)drawPipeline:(menu_display_ctx_draw_t *)draw video:(video_frame_info_t *)video +{ + +} + - (void)draw:(menu_display_ctx_draw_t *)draw video:(video_frame_info_t *)video { Texture *tex = (__bridge Texture *)(void *)draw->texture; @@ -225,30 +230,20 @@ static INLINE void write_quad4a(SpriteVertex *pv, #endif default: { - MTLRenderPassDescriptor *rpd = [MTLRenderPassDescriptor new]; if (_clearNextRender) { - rpd.colorAttachments[0].clearColor = _clearColor; - rpd.colorAttachments[0].loadAction = MTLLoadActionClear; + // TODO(sgc): draw quad to clear _clearNextRender = NO; } - else - { - rpd.colorAttachments[0].loadAction = MTLLoadActionLoad; - } - rpd.colorAttachments[0].storeAction = MTLStoreActionStore; - rpd.colorAttachments[0].texture = _context.nextDrawable.texture; + + id rce = _context.rce; - id cb = _context.commandBuffer; - - id rce = [cb renderCommandEncoderWithDescriptor:rpd]; [rce setRenderPipelineState:[_driver getStockShader:VIDEO_SHADER_STOCK_BLEND blend:_blend]]; [rce setVertexBytes:uniforms length:sizeof(*uniforms) atIndex:BufferIndexUniforms]; [rce setVertexBytes:buf length:sizeof(buf) atIndex:BufferIndexPositions]; [rce setFragmentTexture:tex.texture atIndex:TextureIndexColor]; [rce setFragmentSamplerState:tex.sampler atIndex:SamplerIndexDraw]; [rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4]; - [rce endEncoding]; break; } diff --git a/gfx/common/metal_common.h b/gfx/common/metal_common.h index 821c405bcf..723ecab8da 100644 --- a/gfx/common/metal_common.h +++ b/gfx/common/metal_common.h @@ -46,7 +46,8 @@ extern MTLPixelFormat SelectOptimalPixelFormat(MTLPixelFormat fmt); @interface MetalMenu : NSObject -@property (nonatomic, readwrite) BOOL enabled; +@property (readonly) bool hasFrame; +@property (readwrite) bool enabled; @property (readwrite) float alpha; - (void)updateFrame:(void const *)source; diff --git a/gfx/common/metal_common.m b/gfx/common/metal_common.m index 472b2703ca..bde736be08 100644 --- a/gfx/common/metal_common.m +++ b/gfx/common/metal_common.m @@ -52,7 +52,6 @@ video_info_t _video; - dispatch_semaphore_t _inflightSemaphore; id _device; id _library; Context *_context; @@ -62,7 +61,6 @@ // render target layer state id _t_pipelineState; id _t_pipelineStateNoAlpha; - MTLRenderPassDescriptor *_t_rpd; id _samplerStateLinear; id _samplerStateNearest; @@ -82,7 +80,6 @@ { if (self = [super init]) { - _inflightSemaphore = dispatch_semaphore_create(MAX_INFLIGHT); _device = MTLCreateSystemDefaultDevice(); MetalView *view = (MetalView *)apple_platform.renderView; view.device = _device; @@ -199,13 +196,6 @@ } } - { - MTLRenderPassDescriptor *rpd = [MTLRenderPassDescriptor new]; - rpd.colorAttachments[0].loadAction = MTLLoadActionDontCare; - rpd.colorAttachments[0].storeAction = MTLStoreActionStore; - _t_rpd = rpd; - } - { MTLSamplerDescriptor *sd = [MTLSamplerDescriptor new]; _samplerStateNearest = [_device newSamplerStateWithDescriptor:sd]; @@ -214,6 +204,7 @@ sd.magFilter = MTLSamplerMinMagFilterLinear; _samplerStateLinear = [_device newSamplerStateWithDescriptor:sd]; } + return YES; } @@ -230,7 +221,7 @@ { MTLRenderPipelineDescriptor *psd = [MTLRenderPipelineDescriptor new]; - psd.label = @"stock_blend"; + psd.label = @"stock_no_blend"; MTLRenderPipelineColorAttachmentDescriptor *ca = psd.colorAttachments[0]; ca.pixelFormat = _layer.pixelFormat; @@ -252,7 +243,8 @@ RARCH_ERR("[Metal]: error creating pipeline state %s\n", err.localizedDescription.UTF8String); return NO; } - + + psd.label = @"stock_blend"; ca.blendingEnabled = YES; _states[VIDEO_SHADER_STOCK_BLEND][1] = [_device newRenderPipelineStateWithDescriptor:psd error:&err]; if (err != nil) @@ -335,7 +327,6 @@ assert(!_begin && !_end); _begin = YES; - dispatch_semaphore_wait(_inflightSemaphore, DISPATCH_TIME_FOREVER); [_context begin]; [self _updateUniforms]; } @@ -346,18 +337,14 @@ _begin = NO; _end = YES; - id cb = _context.commandBuffer; - cb.label = @"renderer cb"; + id rce = _context.rce; // draw back buffer + [rce pushDebugGroup:@"core frame"]; [_frameView drawWithContext:_context]; - id drawable = _context.nextDrawable; - _t_rpd.colorAttachments[0].texture = drawable.texture; - if ((_frameView.drawState & ViewDrawStateEncoder) != 0) { - id rce = [cb renderCommandEncoderWithDescriptor:_t_rpd]; [rce setVertexBytes:&_uniforms length:sizeof(_uniforms) atIndex:BufferIndexUniforms]; [rce setRenderPipelineState:_t_pipelineStateNoAlpha]; if (_frameView.filter == RTextureFilterNearest) @@ -369,27 +356,31 @@ [rce setFragmentSamplerState:_samplerStateLinear atIndex:SamplerIndexDraw]; } [_frameView drawWithEncoder:rce]; - [rce endEncoding]; } + [rce popDebugGroup]; #if defined(HAVE_MENU) if (_menu.enabled) { + [rce pushDebugGroup:@"menu"]; menu_driver_frame(video_info); - [_menu.view drawWithContext:_context]; - id rce = [cb renderCommandEncoderWithDescriptor:_t_rpd]; - [rce setVertexBytes:&_uniforms length:sizeof(_uniforms) atIndex:BufferIndexUniforms]; - [rce setRenderPipelineState:_t_pipelineState]; - if (_menu.view.filter == RTextureFilterNearest) + + if (_menu.hasFrame) { - [rce setFragmentSamplerState:_samplerStateNearest atIndex:SamplerIndexDraw]; + [_menu.view drawWithContext:_context]; + [rce setVertexBytes:&_uniforms length:sizeof(_uniforms) atIndex:BufferIndexUniforms]; + [rce setRenderPipelineState:_t_pipelineState]; + if (_menu.view.filter == RTextureFilterNearest) + { + [rce setFragmentSamplerState:_samplerStateNearest atIndex:SamplerIndexDraw]; + } + else + { + [rce setFragmentSamplerState:_samplerStateLinear atIndex:SamplerIndexDraw]; + } + [_menu.view drawWithEncoder:rce]; } - else - { - [rce setFragmentSamplerState:_samplerStateLinear atIndex:SamplerIndexDraw]; - } - [_menu.view drawWithEncoder:rce]; - [rce endEncoding]; + [rce popDebugGroup]; } #endif } @@ -398,14 +389,6 @@ { assert(!_begin && _end); _end = NO; - - id cb = _context.commandBuffer; - __block dispatch_semaphore_t inflight = _inflightSemaphore; - [cb addCompletedHandler:^(id _) { - dispatch_semaphore_signal(inflight); - }]; - - [cb presentDrawable:_context.nextDrawable]; [_context end]; } @@ -444,7 +427,7 @@ { Context *_context; TexturedView *_view; - BOOL _enabled; + bool _enabled; } - (instancetype)initWithContext:(Context *)context @@ -456,14 +439,19 @@ return self; } -- (void)setEnabled:(BOOL)enabled +- (bool)hasFrame +{ + return _view != nil; +} + +- (void)setEnabled:(bool)enabled { if (_enabled == enabled) return; _enabled = enabled; _view.visible = enabled; } -- (BOOL)enabled +- (bool)enabled { return _enabled; } @@ -879,7 +867,7 @@ static vertex_t vertex_bytes[] = { } } - id cb = ctx.commandBuffer; + id cb = ctx.blitCommandBuffer; MTLRenderPassDescriptor *rpd = [MTLRenderPassDescriptor new]; // rpd.colorAttachments[0].clearColor = MTLClearColorMake(0, 0, 0, 1.0); @@ -888,18 +876,20 @@ static vertex_t vertex_bytes[] = { for (unsigned i = 0; i < _shader->passes; i++) { + id rce = nil; + BOOL backBuffer = (_engine.pass[i].rt.view == nil); if (backBuffer) { - rpd.colorAttachments[0].texture = _context.nextDrawable.texture; + rce = _context.rce; } else { rpd.colorAttachments[0].texture = _engine.pass[i].rt.view; + rce = [cb renderCommandEncoderWithDescriptor:rpd]; } - - id rce = [cb renderCommandEncoderWithDescriptor:rpd]; + #if METAL_DEBUG rce.label = [NSString stringWithFormat:@"pass %d", i]; #endif @@ -962,17 +952,19 @@ static vertex_t vertex_bytes[] = { [rce setFragmentSamplerStates:samplers withRange:NSMakeRange(0, SLANG_NUM_BINDINGS)]; [rce setVertexBytes:vertex_bytes length:sizeof(vertex_bytes) atIndex:4]; [rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4]; - [rce endEncoding]; + + if (!backBuffer) + { + [rce endEncoding]; + } + _texture = _engine.pass[i].rt.view; } + if (_texture == nil) - { _drawState = ViewDrawStateContext; - } else - { _drawState = ViewDrawStateAll; - } } - (void)_updateRenderTargets diff --git a/gfx/drivers_font/metal_raster_font.m b/gfx/drivers_font/metal_raster_font.m index 9123af24dc..dcf5e98e3e 100644 --- a/gfx/drivers_font/metal_raster_font.m +++ b/gfx/drivers_font/metal_raster_font.m @@ -32,7 +32,6 @@ id _buffer; id _texture; - MTLRenderPassDescriptor *_rpd; id _state; id _sampler; @@ -163,12 +162,6 @@ static const NSUInteger kConstantAlignment = 4; } } - { - _rpd = [MTLRenderPassDescriptor renderPassDescriptor]; - _rpd.colorAttachments[0].loadAction = MTLLoadActionDontCare; - _rpd.colorAttachments[0].storeAction = MTLStoreActionStore; - } - { MTLSamplerDescriptor *sd = [MTLSamplerDescriptor new]; sd.minFilter = MTLSamplerMinMagFilterLinear; @@ -339,10 +332,8 @@ static INLINE void write_quad6(SpriteVertex *pv, { NSUInteger start = _offset * sizeof(SpriteVertex); [_vert didModifyRange:NSMakeRange(start, sizeof(SpriteVertex) * _vertices)]; - _rpd.colorAttachments[0].texture = _context.nextDrawable.texture; - id cb = _context.commandBuffer; - id rce = [cb renderCommandEncoderWithDescriptor:_rpd]; + id rce = _context.rce; [rce pushDebugGroup:@"render fonts"]; [rce setRenderPipelineState:_state]; [rce setVertexBytes:&_uniforms length:sizeof(_uniforms) atIndex:BufferIndexUniforms]; @@ -351,7 +342,6 @@ static INLINE void write_quad6(SpriteVertex *pv, [rce setFragmentSamplerState:_sampler atIndex:SamplerIndexDraw]; [rce drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:_vertices]; [rce popDebugGroup]; - [rce endEncoding]; _offset += _vertices; _vertices = 0; diff --git a/menu/drivers_display/menu_display_metal.m b/menu/drivers_display/menu_display_metal.m index 5184aefa51..b80702a72b 100644 --- a/menu/drivers_display/menu_display_metal.m +++ b/menu/drivers_display/menu_display_metal.m @@ -34,6 +34,7 @@ static void *menu_display_metal_get_default_mvp(video_frame_info_t *video_info) MetalDriver *md = GET_DRIVER(video_info); if (!md) return NULL; + return (void *)md.viewportMVP; } @@ -67,6 +68,11 @@ static void menu_display_metal_draw(menu_display_ctx_draw_t *draw, static void menu_display_metal_draw_pipeline(menu_display_ctx_draw_t *draw, video_frame_info_t *video_info) { + MetalDriver *md = GET_DRIVER(video_info); + if (!md || !draw) + return; + + [md.display drawPipeline:draw video:video_info]; } static void menu_display_metal_viewport(menu_display_ctx_draw_t *draw, @@ -76,6 +82,7 @@ static void menu_display_metal_viewport(menu_display_ctx_draw_t *draw, static void menu_display_metal_restore_clear_color(void) { + // nothing to do } static void menu_display_metal_clear_color(menu_display_ctx_clearcolor_t *clearcolor,