More cleanup

* use single render command encoder for display for better performance
* Context handles all rendering and presentation
This commit is contained in:
Stuart Carnie 2018-06-30 10:30:43 -07:00
parent 1c5d94aca1
commit 4a101734a1
8 changed files with 112 additions and 85 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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,