mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-24 16:39:43 +00:00
Merge pull request #6948 from stuartcarnie/sgc-metal
feat(Metal): Add support for overlays
This commit is contained in:
commit
95500f5631
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user