mirror of
https://github.com/libretro/RetroArch
synced 2025-03-05 19:13:45 +00:00
More cleanup
* use single render command encoder for display for better performance * Context handles all rendering and presentation
This commit is contained in:
parent
1c5d94aca1
commit
4a101734a1
@ -20,10 +20,18 @@
|
||||
|
||||
@property (readonly) id<MTLDevice> device;
|
||||
@property (readonly) id<MTLLibrary> library;
|
||||
|
||||
/*! @brief Returns the command buffer used for pre-render work,
|
||||
* such as mip maps for applying filters
|
||||
* */
|
||||
@property (readonly) id<MTLCommandBuffer> blitCommandBuffer;
|
||||
|
||||
/*! @brief Returns the command buffer for the current frame */
|
||||
@property (readonly) id<MTLCommandBuffer> commandBuffer;
|
||||
@property (readonly) id<CAMetalDrawable> nextDrawable;
|
||||
@property (readonly) id<MTLTexture> renderTexture;
|
||||
|
||||
/*! @brief Main render encoder to back buffer */
|
||||
@property (readonly) id<MTLRenderCommandEncoder> rce;
|
||||
|
||||
- (instancetype)initWithDevice:(id<MTLDevice>)d
|
||||
layer:(CAMetalLayer *)layer
|
||||
|
@ -16,18 +16,21 @@
|
||||
@end
|
||||
|
||||
@interface Context()
|
||||
@property (readonly) id<MTLCommandBuffer> blitCommandBuffer;
|
||||
- (bool)_initConversionFilters;
|
||||
@end
|
||||
|
||||
@implementation Context
|
||||
{
|
||||
dispatch_semaphore_t _inflightSemaphore;
|
||||
id<MTLCommandQueue> _commandQueue;
|
||||
CAMetalLayer *_layer;
|
||||
id<CAMetalDrawable> _drawable;
|
||||
id<MTLSamplerState> _samplers[TEXTURE_FILTER_MIPMAP_NEAREST + 1];
|
||||
Filter *_filters[RPixelFormatCount]; // convert to bgra8888
|
||||
|
||||
// main render pass state
|
||||
id<MTLRenderCommandEncoder> _rce;
|
||||
|
||||
id<MTLCommandBuffer> _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<MTLTexture>)renderTexture
|
||||
{
|
||||
return self.nextDrawable.texture;
|
||||
}
|
||||
|
||||
- (void)convertFormat:(RPixelFormat)fmt from:(id<MTLBuffer>)src to:(id<MTLTexture>)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<MTLCommandBuffer>)blitCommandBuffer
|
||||
@ -182,9 +189,22 @@
|
||||
- (void)begin
|
||||
{
|
||||
assert(_commandBuffer == nil);
|
||||
dispatch_semaphore_wait(_inflightSemaphore, DISPATCH_TIME_FOREVER);
|
||||
_commandBuffer = [_commandQueue commandBuffer];
|
||||
}
|
||||
|
||||
- (id<MTLRenderCommandEncoder>)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<MTLCommandBuffer> _) {
|
||||
dispatch_semaphore_signal(inflight);
|
||||
}];
|
||||
|
||||
[_commandBuffer presentDrawable:self.nextDrawable];
|
||||
[_commandBuffer commit];
|
||||
|
||||
_commandBuffer = nil;
|
||||
_drawable = nil;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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<MTLRenderCommandEncoder> rce = _context.rce;
|
||||
|
||||
id<MTLCommandBuffer> cb = _context.commandBuffer;
|
||||
|
||||
id<MTLRenderCommandEncoder> 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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -52,7 +52,6 @@
|
||||
|
||||
video_info_t _video;
|
||||
|
||||
dispatch_semaphore_t _inflightSemaphore;
|
||||
id<MTLDevice> _device;
|
||||
id<MTLLibrary> _library;
|
||||
Context *_context;
|
||||
@ -62,7 +61,6 @@
|
||||
// render target layer state
|
||||
id<MTLRenderPipelineState> _t_pipelineState;
|
||||
id<MTLRenderPipelineState> _t_pipelineStateNoAlpha;
|
||||
MTLRenderPassDescriptor *_t_rpd;
|
||||
|
||||
id<MTLSamplerState> _samplerStateLinear;
|
||||
id<MTLSamplerState> _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<MTLCommandBuffer> cb = _context.commandBuffer;
|
||||
cb.label = @"renderer cb";
|
||||
id<MTLRenderCommandEncoder> rce = _context.rce;
|
||||
|
||||
// draw back buffer
|
||||
[rce pushDebugGroup:@"core frame"];
|
||||
[_frameView drawWithContext:_context];
|
||||
|
||||
id<CAMetalDrawable> drawable = _context.nextDrawable;
|
||||
_t_rpd.colorAttachments[0].texture = drawable.texture;
|
||||
|
||||
if ((_frameView.drawState & ViewDrawStateEncoder) != 0)
|
||||
{
|
||||
id<MTLRenderCommandEncoder> 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<MTLRenderCommandEncoder> 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<MTLCommandBuffer> cb = _context.commandBuffer;
|
||||
__block dispatch_semaphore_t inflight = _inflightSemaphore;
|
||||
[cb addCompletedHandler:^(id<MTLCommandBuffer> _) {
|
||||
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<MTLCommandBuffer> cb = ctx.commandBuffer;
|
||||
id<MTLCommandBuffer> 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<MTLRenderCommandEncoder> 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<MTLRenderCommandEncoder> 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
|
||||
|
@ -32,7 +32,6 @@
|
||||
id<MTLBuffer> _buffer;
|
||||
id<MTLTexture> _texture;
|
||||
|
||||
MTLRenderPassDescriptor *_rpd;
|
||||
id<MTLRenderPipelineState> _state;
|
||||
id<MTLSamplerState> _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<MTLCommandBuffer> cb = _context.commandBuffer;
|
||||
id<MTLRenderCommandEncoder> rce = [cb renderCommandEncoderWithDescriptor:_rpd];
|
||||
id<MTLRenderCommandEncoder> 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;
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user