Merge pull request #6948 from stuartcarnie/sgc-metal

feat(Metal): Add support for overlays
This commit is contained in:
Twinaphex 2018-07-04 22:52:29 +02:00 committed by GitHub
commit 95500f5631
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 259 additions and 31 deletions

View File

@ -49,6 +49,7 @@ typedef struct
library:(id<MTLLibrary>)l;
- (Texture *)newTexture:(struct texture_image)image filter:(enum texture_filter_type)filter;
- (id<MTLTexture>)newTexture:(struct texture_image)image mipmapped:(bool)mipmapped;
- (void)convertFormat:(RPixelFormat)fmt from:(id<MTLBuffer>)src to:(id<MTLTexture>)dst;
- (bool)allocRange:(BufferRange *)range length:(NSUInteger)length;

View File

@ -170,9 +170,17 @@
image.height = 8;
}
// TODO(sgc): mipmapping is not working
BOOL mipmapped = filter == TEXTURE_FILTER_MIPMAP_LINEAR || filter == TEXTURE_FILTER_MIPMAP_NEAREST;
Texture *tex = [Texture new];
tex.texture = [self newTexture:image mipmapped:mipmapped];
tex.sampler = _samplers[filter];
return tex;
}
- (id<MTLTexture>)newTexture:(struct texture_image)image mipmapped:(bool)mipmapped
{
MTLTextureDescriptor *td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
width:image.width
height:image.height
@ -192,11 +200,7 @@
[bce endEncoding];
}
Texture *tex = [Texture new];
tex.texture = t;
tex.sampler = _samplers[filter];
return tex;
return t;
}
- (id<CAMetalDrawable>)nextDrawable

View File

@ -58,6 +58,17 @@ extern MTLPixelFormat SelectOptimalPixelFormat(MTLPixelFormat fmt);
filter:(RTextureFilter)filter;
@end
@interface Overlay : NSObject
@property (nonatomic, readwrite) bool enabled;
@property (nonatomic, readwrite) bool fullscreen;
- (bool)loadImages:(const struct texture_image *)images count:(NSUInteger)count;
- (void)updateVertexX:(float)x y:(float)y w:(float)w h:(float)h index:(NSUInteger)index;
- (void)updateTextureCoordsX:(float)x y:(float)y w:(float)w h:(float)h index:(NSUInteger)index;
- (void)updateAlpha:(float)alpha index:(NSUInteger)index;
@end
@interface MetalDriver : NSObject<MTKViewDelegate>
@property (nonatomic, readonly) video_viewport_t *viewport;
@ -65,6 +76,7 @@ extern MTLPixelFormat SelectOptimalPixelFormat(MTLPixelFormat fmt);
@property (nonatomic, readonly) MetalMenu *menu;
@property (nonatomic, readonly) FrameView *frameView;
@property (nonatomic, readonly) MenuDisplay *display;
@property (nonatomic, readonly) Overlay *overlay;
@property (nonatomic, readonly) Context *context;
@property (nonatomic, readonly) Uniforms *viewportMVP;
@property (nonatomic, readonly) Uniforms *viewportMVPNormalized;

View File

@ -45,10 +45,16 @@
- (instancetype)initWithContext:(Context *)context;
@end
@interface Overlay()
- (instancetype)initWithContext:(Context *)context;
- (void)drawWithEncoder:(id<MTLRenderCommandEncoder>)rce;
@end
@implementation MetalDriver
{
FrameView *_frameView;
MetalMenu *_menu;
Overlay *_overlay;
video_info_t _video;
@ -128,6 +134,9 @@
[_frameView setFilteringIndex:0 smooth:video->smooth];
}
// overlay view
_overlay = [[Overlay alloc] initWithContext:_context];
font_driver_init_osd((__bridge void *)self, false, video->is_threaded, FONT_DRIVER_RENDER_METAL_API);
}
return self;
@ -440,6 +449,19 @@
font_driver_render_msg(video_info, NULL, video_info->stat_text, osd_params);
}
}
#ifdef HAVE_OVERLAY
if (_overlay.enabled)
{
id<MTLRenderCommandEncoder> rce = _context.rce;
[rce pushDebugGroup:@"overlay"];
[rce setRenderPipelineState:[self getStockShader:VIDEO_SHADER_STOCK_BLEND blend:YES]];
[rce setVertexBytes:&_uniforms length:sizeof(_uniforms) atIndex:BufferIndexUniforms];
[rce setFragmentSamplerState:_samplerStateLinear atIndex:SamplerIndexDraw];
[_overlay drawWithEncoder:rce];
[rce popDebugGroup];
}
#endif
if (msg && *msg)
{
@ -1462,6 +1484,115 @@ static vertex_t vertex_bytes[] = {
@end
@implementation Overlay
{
Context *_context;
NSMutableArray<id<MTLTexture>> *_images;
id<MTLBuffer> _vert;
bool _vertDirty;
}
- (instancetype)initWithContext:(Context *)context
{
if (self = [super init])
{
_context = context;
}
return self;
}
- (bool)loadImages:(const struct texture_image *)images count:(NSUInteger)count
{
[self _freeImages];
_images = [NSMutableArray arrayWithCapacity:count];
NSUInteger needed = sizeof(SpriteVertex) * count * 4;
if (!_vert || _vert.length < needed)
{
_vert = [_context.device newBufferWithLength:needed options:MTLResourceStorageModeManaged];
}
for (NSUInteger i = 0; i < count; i++)
{
_images[i] = [_context newTexture:images[i] mipmapped:NO];
[self updateVertexX:0 y:0 w:1 h:1 index:i];
[self updateTextureCoordsX:0 y:0 w:1 h:1 index:i];
[self _updateColorRed:1.0 green:1.0 blue:1.0 alpha:1.0 index:i];
}
_vertDirty = YES;
return YES;
}
- (void)drawWithEncoder:(id<MTLRenderCommandEncoder>)rce
{
if (_vertDirty)
{
[_vert didModifyRange:NSMakeRange(0, _vert.length)];
_vertDirty = NO;
}
NSUInteger count = _images.count;
for (NSUInteger i = 0; i < count; ++i)
{
NSUInteger offset = sizeof(SpriteVertex) * 4 * i;
[rce setVertexBuffer:_vert offset:offset atIndex:BufferIndexPositions];
[rce setFragmentTexture:_images[i] atIndex:TextureIndexColor];
[rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
}
}
- (SpriteVertex *)_getForIndex:(NSUInteger)index
{
SpriteVertex *pv = (SpriteVertex *)_vert.contents;
return &pv[index * 4];
}
- (void)_updateColorRed:(float)r green:(float)g blue:(float)b alpha:(float)a index:(NSUInteger)index
{
simd_float4 color = simd_make_float4(r, g, b, a);
SpriteVertex *pv = [self _getForIndex:index];
pv[0].color = color;
pv[1].color = color;
pv[2].color = color;
pv[3].color = color;
_vertDirty = YES;
}
- (void)updateAlpha:(float)alpha index:(NSUInteger)index
{
[self _updateColorRed:1.0 green:1.0 blue:1.0 alpha:alpha index:index];
}
- (void)updateVertexX:(float)x y:(float)y w:(float)w h:(float)h index:(NSUInteger)index
{
SpriteVertex *pv = [self _getForIndex:index];
pv[0].position = simd_make_float2(x, y);
pv[1].position = simd_make_float2(x + w, y);
pv[2].position = simd_make_float2(x, y + h);
pv[3].position = simd_make_float2(x + w, y + h);
_vertDirty = YES;
}
- (void)updateTextureCoordsX:(float)x y:(float)y w:(float)w h:(float)h index:(NSUInteger)index
{
SpriteVertex *pv = [self _getForIndex:index];
pv[0].texCoord = simd_make_float2(x, y);
pv[1].texCoord = simd_make_float2(x + w, y);
pv[2].texCoord = simd_make_float2(x, y + h);
pv[3].texCoord = simd_make_float2(x + w, y + h);
_vertDirty = YES;
}
- (void)_freeImages
{
_images = nil;
}
@end
MTLPixelFormat glslang_format_to_metal(glslang_format fmt)
{
#undef FMT2

View File

@ -92,12 +92,10 @@ static bool metal_focus(void *data)
return apple_platform.hasFocus;
}
static bool metal_suppress_screensaver(void *data, bool enable)
static bool metal_suppress_screensaver(void *data, bool disable)
{
bool enabled = enable;
(void)data;
return video_context_driver_suppress_screensaver(&enabled);
RARCH_LOG("[Metal]: suppress screen saver: %s\n", disable ? "YES" : "NO");
return [apple_platform setDisableDisplaySleep:disable];
}
static bool metal_set_shader(void *data,
@ -149,26 +147,6 @@ static bool metal_read_viewport(void *data, uint8_t *buffer, bool is_idle)
return true;
}
#ifdef HAVE_OVERLAY
static const video_overlay_interface_t metal_overlay_interface = {
// metal_overlay_enable,
// metal_overlay_load,
// metal_overlay_tex_geom,
// metal_overlay_vertex_geom,
// metal_overlay_full_screen,
// metal_overlay_set_alpha,
};
static void metal_get_overlay_interface(void *data,
const video_overlay_interface_t **iface)
{
(void)data;
*iface = &metal_overlay_interface;
}
#endif
static uintptr_t metal_load_texture(void *video_data, void *data,
bool threaded, enum texture_filter_type filter_type)
{
@ -337,6 +315,82 @@ static void metal_get_poke_interface(void *data,
*iface = &metal_poke_interface;
}
#ifdef HAVE_OVERLAY
static void metal_overlay_enable(void *data, bool state)
{
MetalDriver *md = (__bridge MetalDriver *)data;
if (!md)
return;
md.overlay.enabled = state;
}
static bool metal_overlay_load(void *data,
const void *images, unsigned num_images)
{
MetalDriver *md = (__bridge MetalDriver *)data;
if (!md)
return NO;
return [md.overlay loadImages:(const struct texture_image *)images count:num_images];
}
static void metal_overlay_tex_geom(void *data, unsigned index,
float x, float y, float w, float h)
{
MetalDriver *md = (__bridge MetalDriver *)data;
if (!md)
return;
[md.overlay updateTextureCoordsX:x y:y w:w h:h index:index];
}
static void metal_overlay_vertex_geom(void *data, unsigned index,
float x, float y, float w, float h)
{
MetalDriver *md = (__bridge MetalDriver *)data;
if (!md)
return;
[md.overlay updateVertexX:x y:y w:w h:h index:index];
}
static void metal_overlay_full_screen(void *data, bool enable)
{
MetalDriver *md = (__bridge MetalDriver *)data;
if (!md)
return;
md.overlay.fullscreen = enable;
}
static void metal_overlay_set_alpha(void *data, unsigned index, float mod)
{
MetalDriver *md = (__bridge MetalDriver *)data;
if (!md)
return;
[md.overlay updateAlpha:mod index:index];
}
static const video_overlay_interface_t metal_overlay_interface = {
.enable = metal_overlay_enable,
.load = metal_overlay_load,
.tex_geom = metal_overlay_tex_geom,
.vertex_geom = metal_overlay_vertex_geom,
.full_screen = metal_overlay_full_screen,
.set_alpha = metal_overlay_set_alpha,
};
static void metal_get_overlay_interface(void *data,
const video_overlay_interface_t **iface)
{
(void)data;
*iface = &metal_overlay_interface;
}
#endif
video_driver_t video_metal = {
.init = metal_init,

View File

@ -60,6 +60,10 @@ typedef enum apple_view_type {
/*! @brief setCursorVisible specifies whether the cursor is visible */
- (void)setCursorVisible:(bool)v;
/*! @brief controls whether the screen saver should be disabled and
* the displays should not sleep.
*/
- (bool)setDisableDisplaySleep:(bool)disable;
@end
extern id<ApplePlatform> apple_platform;

View File

@ -53,6 +53,8 @@ id<ApplePlatform> apple_platform;
NSWindow* _window;
apple_view_type_t _vt;
NSView* _renderView;
id _sleepActivity;
}
@property (nonatomic, retain) NSWindow IBOutlet* window;
@ -337,6 +339,26 @@ static char** waiting_argv;
[NSCursor hide];
}
- (bool)setDisableDisplaySleep:(bool)disable
{
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
if (disable && _sleepActivity == nil)
{
_sleepActivity = [NSProcessInfo.processInfo beginActivityWithOptions:NSActivityIdleDisplaySleepDisabled reason:@"disable screen saver"];
}
else if (!disable && _sleepActivity != nil)
{
[NSProcessInfo.processInfo endActivity:_sleepActivity];
_sleepActivity = nil;
}
return YES;
#else
return NO;
#endif
}
- (void) rarch_main
{
do