feat(Metal): initial xmb and glui menu support

TODOs

* menu shader pipeline effects
* refactor / optimize graphics rendering
This commit is contained in:
Stuart Carnie 2018-06-29 22:57:48 -07:00
parent 4135300b04
commit 5e1f991e32
26 changed files with 1753 additions and 1135 deletions

View File

@ -8,9 +8,14 @@
#import <Foundation/Foundation.h>
#import <Metal/Metal.h>
#import "RendererCommon.h"
NS_ASSUME_NONNULL_BEGIN
@interface Texture : NSObject
@property (readonly) id<MTLTexture> texture;
@property (readonly) id<MTLSamplerState> sampler;
@end
/*! @brief Context contains the render state used by various components */
@interface Context : NSObject
@property (readonly) id<MTLDevice> device;
@ -21,10 +26,12 @@ NS_ASSUME_NONNULL_BEGIN
@property (readonly) id<CAMetalDrawable> nextDrawable;
@property (readonly) id<MTLTexture> renderTexture;
+ (instancetype)newContextWithDevice:(id<MTLDevice>)d
layer:(CAMetalLayer *)layer
library:(id<MTLLibrary>)l
commandQueue:(id<MTLCommandQueue>)q;
- (instancetype)initWithDevice:(id<MTLDevice>)d
layer:(CAMetalLayer *)layer
library:(id<MTLLibrary>)l;
- (Texture *)newTexture:(struct texture_image)image filter:(enum texture_filter_type)filter;
- (void)convertFormat:(RPixelFormat)fmt from:(id<MTLBuffer>)src to:(id<MTLTexture>)dst;
/*! @brief begin marks the beginning of a frame */
- (void)begin;
@ -33,5 +40,3 @@ NS_ASSUME_NONNULL_BEGIN
- (void)end;
@end
NS_ASSUME_NONNULL_END

View File

@ -7,43 +7,178 @@
//
#import "Context.h"
#import "Filter.h"
#import <QuartzCore/QuartzCore.h>
@interface Context()
{
CAMetalLayer *_layer;
id<CAMetalDrawable> _drawable;
}
@interface Texture()
@property (readwrite) id<MTLTexture> texture;
@property (readwrite) id<MTLSamplerState> sampler;
@end
@interface Context()
@property (readonly) id<MTLCommandBuffer> blitCommandBuffer;
- (bool)_initConversionFilters;
@end
@implementation Context
+ (instancetype)newContextWithDevice:(id<MTLDevice>)d
layer:(CAMetalLayer *)layer
library:(id<MTLLibrary>)l
commandQueue:(id<MTLCommandQueue>)q
{
Context *c = [Context new];
c->_device = d;
c->_layer = layer;
c->_library = l;
c->_commandQueue = q;
return c;
id<MTLCommandQueue> _commandQueue;
CAMetalLayer *_layer;
id<CAMetalDrawable> _drawable;
id<MTLSamplerState> _samplers[TEXTURE_FILTER_MIPMAP_NEAREST + 1];
Filter *_filters[RPixelFormatCount]; // convert to bgra8888
id<MTLCommandBuffer> _blitCommandBuffer;
}
- (id<CAMetalDrawable>)nextDrawable {
if (_drawable == nil) {
- (instancetype)initWithDevice:(id<MTLDevice>)d
layer:(CAMetalLayer *)layer
library:(id<MTLLibrary>)l
{
if (self = [super init])
{
_device = d;
_layer = layer;
_library = l;
_commandQueue = [_device newCommandQueue];
MTLSamplerDescriptor *sd = [MTLSamplerDescriptor new];
sd.label = @"NEAREST";
_samplers[TEXTURE_FILTER_NEAREST] = [d newSamplerStateWithDescriptor:sd];
sd.mipFilter = MTLSamplerMipFilterNearest;
sd.label = @"MIPMAP_NEAREST";
_samplers[TEXTURE_FILTER_MIPMAP_NEAREST] = [d newSamplerStateWithDescriptor:sd];
sd.mipFilter = MTLSamplerMipFilterNotMipmapped;
sd.minFilter = MTLSamplerMinMagFilterLinear;
sd.magFilter = MTLSamplerMinMagFilterLinear;
sd.label = @"LINEAR";
_samplers[TEXTURE_FILTER_LINEAR] = [d newSamplerStateWithDescriptor:sd];
sd.mipFilter = MTLSamplerMipFilterLinear;
sd.label = @"MIPMAP_LINEAR";
_samplers[TEXTURE_FILTER_MIPMAP_LINEAR] = [d newSamplerStateWithDescriptor:sd];
if (![self _initConversionFilters])
return nil;
}
return self;
}
- (bool)_initConversionFilters
{
NSError *err = nil;
_filters[RPixelFormatBGRA4Unorm] = [Filter newFilterWithFunctionName:@"convert_bgra4444_to_bgra8888"
device:_device
library:_library
error:&err];
if (err)
{
RARCH_LOG("[Metal]: unable to create 'convert_bgra4444_to_bgra8888' conversion filter: %s\n",
err.localizedDescription.UTF8String);
return NO;
}
_filters[RPixelFormatB5G6R5Unorm] = [Filter newFilterWithFunctionName:@"convert_rgb565_to_bgra8888"
device:_device
library:_library
error:&err];
if (err)
{
RARCH_LOG("[Metal]: unable to create 'convert_rgb565_to_bgra8888' conversion filter: %s\n",
err.localizedDescription.UTF8String);
return NO;
}
return YES;
}
- (Texture *)newTexture:(struct texture_image)image filter:(enum texture_filter_type)filter
{
if (!image.pixels && !image.width && !image.height)
{
/* Create a dummy texture instead. */
#define T0 0xff000000u
#define T1 0xffffffffu
static const uint32_t checkerboard[] = {
T0, T1, T0, T1, T0, T1, T0, T1,
T1, T0, T1, T0, T1, T0, T1, T0,
T0, T1, T0, T1, T0, T1, T0, T1,
T1, T0, T1, T0, T1, T0, T1, T0,
T0, T1, T0, T1, T0, T1, T0, T1,
T1, T0, T1, T0, T1, T0, T1, T0,
T0, T1, T0, T1, T0, T1, T0, T1,
T1, T0, T1, T0, T1, T0, T1, T0,
};
#undef T0
#undef T1
image.pixels = (uint32_t *)checkerboard;
image.width = 8;
image.height = 8;
}
// TODO(sgc): mipmapping is not working
BOOL mipmapped = filter == TEXTURE_FILTER_MIPMAP_LINEAR || filter == TEXTURE_FILTER_MIPMAP_NEAREST;
MTLTextureDescriptor *td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
width:image.width
height:image.height
mipmapped:mipmapped];
id<MTLTexture> t = [_device newTextureWithDescriptor:td];
[t replaceRegion:MTLRegionMake2D(0, 0, image.width, image.height)
mipmapLevel:0
withBytes:image.pixels
bytesPerRow:4 * image.width];
if (mipmapped)
{
id<MTLCommandBuffer> cb = self.blitCommandBuffer;
id<MTLBlitCommandEncoder> bce = [cb blitCommandEncoder];
[bce generateMipmapsForTexture:t];
[bce endEncoding];
}
Texture *tex = [Texture new];
tex.texture = t;
tex.sampler = _samplers[filter];
return tex;
}
- (id<CAMetalDrawable>)nextDrawable
{
if (_drawable == nil)
{
_drawable = _layer.nextDrawable;
}
return _drawable;
}
- (id<MTLTexture>)renderTexture {
- (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];
}
- (id<MTLCommandBuffer>)blitCommandBuffer
{
if (!_blitCommandBuffer)
_blitCommandBuffer = [_commandQueue commandBuffer];
return _blitCommandBuffer;
}
- (void)begin
{
assert(_commandBuffer == nil);
@ -53,9 +188,21 @@
- (void)end
{
assert(self->_commandBuffer != nil);
if (_blitCommandBuffer)
{
// pending blits for mipmaps
[_blitCommandBuffer commit];
[_blitCommandBuffer waitUntilCompleted];
_blitCommandBuffer = nil;
}
[_commandBuffer commit];
_commandBuffer = nil;
_drawable = nil;
}
@end
@implementation Texture
@end

View File

@ -0,0 +1,27 @@
//
// Created by Stuart Carnie on 6/24/18.
//
#import <Foundation/Foundation.h>
#import "ShaderTypes.h"
@class Context;
@class MetalDriver;
@interface MenuDisplay : NSObject
@property (readwrite) BOOL blend;
@property (readwrite) MTLClearColor clearColor;
- (instancetype)initWithDriver:(MetalDriver *)driver;
- (void)draw:(menu_display_ctx_draw_t *)draw video:(video_frame_info_t *)video;
#pragma mark - static methods
+ (const float *)defaultVertices;
+ (const float *)defaultTexCoords;
+ (const float *)defaultColor;
+ (const float *)defaultMatrix;
@end

View File

@ -0,0 +1,257 @@
//
// Created by Stuart Carnie on 6/24/18.
//
#import "Context.h"
#import "MenuDisplay.h"
#import "ShaderTypes.h"
#import "menu_driver.h"
#import <Metal/Metal.h>
// TODO(sgc): this dependency is incorrect
#import "../metal_common.h"
@implementation MenuDisplay
{
__weak MetalDriver *_driver;
Context *_context;
MTLClearColor _clearColor;
bool _clearNextRender;
Uniforms _uniforms;
}
- (instancetype)initWithDriver:(MetalDriver *)driver
{
if (self = [super init])
{
_driver = driver;
_context = driver.context;
_clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
_uniforms.projectionMatrix = matrix_proj_ortho(0, 1, 0, 1);
}
return self;
}
+ (const float *)defaultVertices
{
static float dummy[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};
return &dummy[0];
}
+ (const float *)defaultTexCoords
{
static float dummy[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};
return &dummy[0];
}
+ (const float *)defaultColor
{
static float dummy[] = {
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
};
return &dummy[0];
}
+ (const float *)defaultMatrix
{
static matrix_float4x4 dummy;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dummy = matrix_proj_ortho(0, 1, 0, 1);
});
return &dummy;
}
- (void)setClearColor:(MTLClearColor)clearColor
{
_clearColor = clearColor;
_clearNextRender = YES;
}
- (MTLClearColor)clearColor
{
return _clearColor;
}
- (MTLPrimitiveType)_toPrimitiveType:(enum menu_display_prim_type)prim
{
switch (prim)
{
case MENU_DISPLAY_PRIM_TRIANGLESTRIP:
return MTLPrimitiveTypeTriangleStrip;
case MENU_DISPLAY_PRIM_TRIANGLES:
return MTLPrimitiveTypeTriangle;
default:
RARCH_LOG("unexpected primitive type %d\n", prim);
return MTLPrimitiveTypeTriangle;
}
}
static INLINE void write_quad4(SpriteVertex *pv,
float x, float y, float width, float height, float scale,
float tex_x, float tex_y, float tex_width, float tex_height,
const float *color)
{
unsigned i;
static const float strip[2 * 4] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};
float swidth = width * scale;
float sheight = height * scale;
x += (width - swidth) / 2;
y += (height - sheight) / 2;
for (i = 0; i < 4; i++)
{
pv[i].position = simd_make_float2(x + strip[2 * i + 0] * swidth,
y + strip[2 * i + 1] * sheight);
pv[i].texCoord = simd_make_float2(tex_x + strip[2 * i + 0] * tex_width,
tex_y + strip[2 * i + 1] * tex_height);
pv[i].color = simd_make_float4(color[0], color[1], color[2], color[3]);
color += 4;
}
}
static INLINE void write_quad4a(SpriteVertex *pv,
float x, float y, float width, float height, float scale,
float tex_x, float tex_y, float tex_width, float tex_height,
const float *color)
{
unsigned i;
static const float vert[2 * 4] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};
static const float tex[2 * 4] = {
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
};
float swidth = width * scale;
float sheight = height * scale;
x += (width - swidth) / 2;
y += (height - sheight) / 2;
for (i = 0; i < 4; i++)
{
pv[i].position = simd_make_float2(x + vert[2 * i + 0] * swidth,
y + vert[2 * i + 1] * sheight);
pv[i].texCoord = simd_make_float2(tex_x + tex[2 * i + 0] * tex_width,
tex_y + tex[2 * i + 1] * tex_height);
pv[i].color = simd_make_float4(color[0], color[1], color[2], color[3]);
color += 4;
}
}
- (void)draw:(menu_display_ctx_draw_t *)draw video:(video_frame_info_t *)video
{
Texture *tex = (__bridge Texture *)(void *)draw->texture;
const float *vertex = draw->coords->vertex;
const float *tex_coord = draw->coords->tex_coord;
const float *color = draw->coords->color;
if (!vertex)
vertex = MenuDisplay.defaultVertices;
if (!tex_coord)
tex_coord = MenuDisplay.defaultTexCoords;
if (!draw->coords->lut_tex_coord)
draw->coords->lut_tex_coord = MenuDisplay.defaultTexCoords;
// TODO(sgc): is this necessary?
// if (!texture)
// texture = &vk->display.blank_texture;
if (!color)
color = MenuDisplay.defaultColor;
assert(draw->coords->vertices <= 4);
SpriteVertex buf[4];
SpriteVertex *pv = buf;
Uniforms *uniforms;
if (draw->coords->vertex == NULL)
{
write_quad4a(pv,
draw->x,
draw->y,
draw->width,
draw->height,
draw->scale_factor,
0.0, 0.0, 1.0, 1.0, color);
uniforms = _driver.viewportMVP;
}
else
{
for (unsigned i = 0; i < draw->coords->vertices; i++, pv++)
{
/* Y-flip. We're using top-left coordinates */
pv->position = simd_make_float2(vertex[0], vertex[1]);
vertex += 2;
pv->texCoord = simd_make_float2(tex_coord[0], tex_coord[1]);
tex_coord += 2;
pv->color = simd_make_float4(color[0], color[1], color[2], color[3]);
color += 4;
}
uniforms = &_uniforms;
}
switch (draw->pipeline.id)
{
#ifdef HAVE_SHADERPIPELINE
#endif
default:
{
MTLRenderPassDescriptor *rpd = [MTLRenderPassDescriptor new];
if (_clearNextRender)
{
rpd.colorAttachments[0].clearColor = _clearColor;
rpd.colorAttachments[0].loadAction = MTLLoadActionClear;
_clearNextRender = NO;
}
else
{
rpd.colorAttachments[0].loadAction = MTLLoadActionLoad;
}
rpd.colorAttachments[0].storeAction = MTLStoreActionStore;
rpd.colorAttachments[0].texture = _context.nextDrawable.texture;
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;
}
}
}
@end

View File

@ -1,10 +0,0 @@
//
// MetalRenderer.h
// MetalRenderer
//
// Created by Stuart Carnie on 6/7/18.
// Copyright © 2018 Stuart Carnie. All rights reserved.
//
#import "Renderer.h"
#import "RView.h"

View File

@ -1,13 +0,0 @@
//
// PixelConverter+private.h
// MetalRenderer
//
// Created by Stuart Carnie on 6/9/18.
// Copyright © 2018 Stuart Carnie. All rights reserved.
//
#import "PixelConverter.h"
#import "Context.h"
@interface PixelConverter()
- (instancetype)initWithContext:(Context *)c;
@end

View File

@ -1,20 +0,0 @@
//
// PixelConverter.h
// MetalRenderer
//
// Created by Stuart Carnie on 6/9/18.
// Copyright © 2018 Stuart Carnie. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <Metal/Metal.h>
#import "RendererCommon.h"
NS_ASSUME_NONNULL_BEGIN
@interface PixelConverter : NSObject
- (void)convertFormat:(RPixelFormat)fmt from:(id<MTLBuffer>)src to:(id<MTLTexture>)dst;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,49 +0,0 @@
//
// PixelConverter.m
// MetalRenderer
//
// Created by Stuart Carnie on 6/9/18.
// Copyright © 2018 Stuart Carnie. All rights reserved.
//
#import "PixelConverter+private.h"
#import "Filter.h"
#import "Context.h"
@implementation PixelConverter {
Context *_context;
Filter *_filters[RPixelFormatCount]; // convert to bgra8888
}
- (instancetype)initWithContext:(Context *)c
{
if (self = [super init])
{
_context = c;
NSError *err = nil;
_filters[RPixelFormatBGRA4Unorm] = [Filter newFilterWithFunctionName:@"convert_bgra4444_to_bgra8888"
device:c.device library:c.library
error:&err];
_filters[RPixelFormatB5G6R5Unorm] = [Filter newFilterWithFunctionName:@"convert_rgb565_to_bgra8888"
device:c.device
library:c.library
error:&err];
if (err)
{
NSLog(@"unable to create pixel conversion filter: %@", err.localizedDescription);
abort();
}
}
return self;
}
- (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:_context.commandBuffer inBuf:src outTex:dst];
}
@end

View File

@ -1,49 +0,0 @@
//
// PixelConverter.metal
// MetalRenderer
//
// Created by Stuart Carnie on 6/9/18.
// Copyright © 2018 Stuart Carnie. All rights reserved.
//
#include <metal_stdlib>
using namespace metal;
#pragma mark - filter kernels
kernel void convert_bgra4444_to_bgra8888(device uint16_t * in [[ buffer(0) ]],
texture2d<half, access::write> out [[ texture(0) ]],
uint id [[ thread_position_in_grid ]])
{
uint16_t pix = in[id];
uchar4 pix2 = uchar4(
extract_bits(pix, 4, 4),
extract_bits(pix, 8, 4),
extract_bits(pix, 12, 4),
extract_bits(pix, 0, 4)
);
uint ypos = id / out.get_width();
uint xpos = id % out.get_width();
out.write(half4(pix2) / 15.0, uint2(xpos, ypos));
}
kernel void convert_rgb565_to_bgra8888(device uint16_t * in [[ buffer(0) ]],
texture2d<half, access::write> out [[ texture(0) ]],
uint id [[ thread_position_in_grid ]])
{
uint16_t pix = in[id];
uchar4 pix2 = uchar4(
extract_bits(pix, 11, 5),
extract_bits(pix, 5, 6),
extract_bits(pix, 0, 5),
0xf
);
uint ypos = id / out.get_width();
uint xpos = id % out.get_width();
out.write(half4(pix2) / half4(0x1f, 0x3f, 0x1f, 0xf), uint2(xpos, ypos));
}

View File

@ -1,37 +0,0 @@
//
// Renderer.h
// MetalRenderer
//
// Created by Stuart Carnie on 5/31/18.
// Copyright © 2018 Stuart Carnie. All rights reserved.
//
#import <Metal/Metal.h>
#import <QuartzCore/QuartzCore.h>
#import "Context.h"
#import "PixelConverter.h"
@protocol View;
@interface Renderer : NSObject
@property (readonly) Context* context;
@property (readonly) PixelConverter* conv;
- (instancetype)initWithDevice:(id<MTLDevice>)device layer:(CAMetalLayer *)layer;
- (void)drawableSizeWillChange:(CGSize)size;
- (void)beginFrame;
- (void)drawViews;
- (void)endFrame;
#pragma mark - view management
- (void)addView:(id<View>)view;
- (void)removeView:(id<View>)view;
- (void)bringViewToFront:(id<View>)view;
- (void)sendViewToBack:(id<View>)view;
@end

View File

@ -1,263 +0,0 @@
//
// Renderer.m
// MetalRenderer
//
// Created by Stuart Carnie on 5/31/18.
// Copyright © 2018 Stuart Carnie. All rights reserved.
//
#import <simd/simd.h>
#import "RendererCommon.h"
#import "Renderer.h"
#import "View.h"
#import "PixelConverter+private.h"
// Include header shared between C code here, which executes Metal API commands, and .metal files
#import "ShaderTypes.h"
@implementation Renderer
{
dispatch_semaphore_t _inflightSemaphore;
id<MTLDevice> _device;
id<MTLLibrary> _library;
id<MTLCommandQueue> _commandQueue;
Context *_context;
PixelConverter *_conv;
CAMetalLayer *_layer;
// render target layer state
id<MTLRenderPipelineState> _t_pipelineState;
id<MTLRenderPipelineState> _t_pipelineStateNoAlpha;
MTLRenderPassDescriptor *_t_rpd;
id<MTLSamplerState> _samplerStateLinear;
id<MTLSamplerState> _samplerStateNearest;
// views
NSMutableArray<id<View>> *_views;
// other state
Uniforms _uniforms;
BOOL _begin, _end;
}
- (instancetype)initWithDevice:(id<MTLDevice>)device layer:(CAMetalLayer *)layer
{
self = [super init];
if (self) {
_inflightSemaphore = dispatch_semaphore_create(MAX_INFLIGHT);
_device = device;
_layer = layer;
_views = [NSMutableArray new];
[self _initMetal];
_conv = [[PixelConverter alloc] initWithContext:_context];
_begin = NO;
_end = NO;
}
return self;
}
- (void)_initMetal
{
_commandQueue = [_device newCommandQueue];
_library = [_device newDefaultLibrary];
_context = [Context newContextWithDevice:_device
layer:_layer
library:_library
commandQueue:_commandQueue];
{
MTLVertexDescriptor *vd = [MTLVertexDescriptor new];
vd.attributes[0].offset = 0;
vd.attributes[0].format = MTLVertexFormatFloat3;
vd.attributes[1].offset = offsetof(Vertex, texCoord);
vd.attributes[1].format = MTLVertexFormatFloat2;
vd.layouts[0].stride = sizeof(Vertex);
vd.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
MTLRenderPipelineDescriptor *psd = [MTLRenderPipelineDescriptor new];
psd.label = @"Pipeline+Alpha";
MTLRenderPipelineColorAttachmentDescriptor *ca = psd.colorAttachments[0];
ca.pixelFormat = _layer.pixelFormat;
ca.blendingEnabled = YES;
ca.sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha;
ca.sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
ca.destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
ca.destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
psd.sampleCount = 1;
psd.vertexDescriptor = vd;
psd.vertexFunction = [_library newFunctionWithName:@"basic_vertex_proj_tex"];
psd.fragmentFunction = [_library newFunctionWithName:@"basic_fragment_proj_tex"];
NSError *err;
_t_pipelineState = [_device newRenderPipelineStateWithDescriptor:psd error:&err];
if (err != nil) {
NSLog(@"error creating pipeline state: %@", err.localizedDescription);
abort();
}
ca.blendingEnabled = NO;
_t_pipelineStateNoAlpha = [_device newRenderPipelineStateWithDescriptor:psd error:&err];
if (err != nil) {
NSLog(@"error creating pipeline state: %@", err.localizedDescription);
abort();
}
}
{
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];
sd.minFilter = MTLSamplerMinMagFilterLinear;
sd.magFilter = MTLSamplerMinMagFilterLinear;
_samplerStateLinear = [_device newSamplerStateWithDescriptor:sd];
}
}
- (void)_updateUniforms
{
//CGSize s = _layer.drawableSize;
//_uniforms.projectionMatrix = matrix_proj_ortho(0, s.width, 0, s.height);
_uniforms.projectionMatrix = matrix_proj_ortho(0, 1, 0, 1);
}
- (void)beginFrame
{
assert(!_begin && !_end);
_begin = YES;
dispatch_semaphore_wait(_inflightSemaphore, DISPATCH_TIME_FOREVER);
[_context begin];
[self _updateUniforms];
}
- (void)endFrame
{
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];
}
- (void)drawViews
{
@autoreleasepool {
assert(_begin && !_end);
_begin = NO;
_end = YES;
id<MTLCommandBuffer> cb = _context.commandBuffer;
cb.label = @"renderer cb";
for (id<View> v in _views) {
if (!v.visible) continue;
if ([v respondsToSelector:@selector(drawWithContext:)]) {
[v drawWithContext:_context];
}
}
BOOL pendingDraws = NO;
for (id<View> v in _views) {
if (v.visible && (v.drawState & ViewDrawStateEncoder) != 0) {
pendingDraws = YES;
break;
}
}
if (pendingDraws) {
id<CAMetalDrawable> drawable = _context.nextDrawable;
_t_rpd.colorAttachments[0].texture = drawable.texture;
id<MTLRenderCommandEncoder> rce = [cb renderCommandEncoderWithDescriptor:_t_rpd];
[rce setVertexBytes:&_uniforms length:sizeof(_uniforms) atIndex:BufferIndexUniforms];
for (id<View> v in _views) {
if (!v.visible ||
![v respondsToSelector:@selector(drawWithEncoder:)] ||
(v.drawState & ViewDrawStateEncoder) == 0) {
continue;
}
// set view state
if (v.format == RPixelFormatBGRX8Unorm || v.format == RPixelFormatB5G6R5Unorm) {
[rce setRenderPipelineState:_t_pipelineStateNoAlpha];
}
else {
[rce setRenderPipelineState:_t_pipelineState];
}
if (v.filter == RTextureFilterNearest) {
[rce setFragmentSamplerState:_samplerStateNearest atIndex:SamplerIndexDraw];
}
else {
[rce setFragmentSamplerState:_samplerStateLinear atIndex:SamplerIndexDraw];
}
[v drawWithEncoder:rce];
}
[rce endEncoding];
}
}
}
#pragma mark - view APIs
- (void)bringViewToFront:(id<View>)view
{
NSUInteger pos = [_views indexOfObject:view];
if (pos == NSNotFound || pos == _views.count - 1)
return;
[_views removeObjectAtIndex:pos];
[_views addObject:view];
}
- (void)sendViewToBack:(id<View>)view
{
NSUInteger pos = [_views indexOfObject:view];
if (pos == NSNotFound || pos == 0)
return;
[_views removeObjectAtIndex:pos];
[_views insertObject:view atIndex:0];
}
- (void)addView:(id<View>)view
{
[_views addObject:view];
}
- (void)removeView:(id<View>)view
{
NSUInteger pos = [_views indexOfObject:view];
if (pos == NSNotFound)
return;
[_views removeObjectAtIndex:pos];
}
- (void)drawableSizeWillChange:(CGSize)size
{
_layer.drawableSize = size;
}
@end

View File

@ -11,64 +11,62 @@
NSUInteger RPixelFormatToBPP(RPixelFormat format)
{
switch (format)
{
case RPixelFormatBGRA8Unorm:
case RPixelFormatBGRX8Unorm:
return 4;
case RPixelFormatB5G6R5Unorm:
case RPixelFormatBGRA4Unorm:
return 2;
default:
NSLog(@"Unknown format %ld", format);
abort();
}
switch (format) {
case RPixelFormatBGRA8Unorm:
case RPixelFormatBGRX8Unorm:
return 4;
case RPixelFormatB5G6R5Unorm:
case RPixelFormatBGRA4Unorm:
return 2;
default:
RARCH_ERR("[Metal]: unknown RPixel format: %d\n", format);
return 4;
}
}
static NSString * RPixelStrings[RPixelFormatCount];
static NSString *RPixelStrings[RPixelFormatCount];
NSString *NSStringFromRPixelFormat(RPixelFormat format)
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
#define STRING(literal) RPixelStrings[literal] = @#literal
STRING(RPixelFormatInvalid);
STRING(RPixelFormatB5G6R5Unorm);
STRING(RPixelFormatBGRA4Unorm);
STRING(RPixelFormatBGRA8Unorm);
STRING(RPixelFormatBGRX8Unorm);
STRING(RPixelFormatInvalid);
STRING(RPixelFormatB5G6R5Unorm);
STRING(RPixelFormatBGRA4Unorm);
STRING(RPixelFormatBGRA8Unorm);
STRING(RPixelFormatBGRX8Unorm);
#undef STRING
});
if (format >= RPixelFormatCount)
{
format = 0;
}
return RPixelStrings[format];
});
if (format >= RPixelFormatCount) {
format = RPixelFormatInvalid;
}
return RPixelStrings[format];
}
matrix_float4x4 matrix_proj_ortho(float left, float right, float top, float bottom)
{
float near = 0;
float far = 1;
float sx = 2 / (right - left);
float sy = 2 / (top - bottom);
float sz = 1 / (far - near);
float tx = (right + left) / (left - right);
float ty = (top + bottom) / (bottom - top);
float tz = near / (far - near);
vector_float4 P = {sx, 0, 0, 0};
vector_float4 Q = {0, sy, 0, 0};
vector_float4 R = {0, 0, sz, 0};
vector_float4 S = {tx, ty, tz, 1};
simd_float4 P = {sx, 0, 0, 0};
simd_float4 Q = {0, sy, 0, 0};
simd_float4 R = {0, 0, sz, 0};
simd_float4 S = {tx, ty, tz, 1};
matrix_float4x4 mat = {P, Q, R, S};
return mat;
}

View File

@ -13,49 +13,44 @@
#define ShaderTypes_h
#ifdef __METAL_VERSION__
#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#define NSInteger metal::int32_t
#define METAL_ATTRIBUTE(x) [[attribute(x)]]
#define METAL_POSITION [[position]]
#else
#import <Foundation/Foundation.h>
#define METAL_ATTRIBUTE(x)
#define METAL_POSITION
#endif
#include <simd/simd.h>
typedef NS_ENUM(NSInteger, BufferIndex)
{
BufferIndexPositions = 0,
BufferIndexUniforms = 1
BufferIndexPositions = 0,
BufferIndexUniforms = 1
};
typedef NS_ENUM(NSInteger, VertexAttribute)
{
VertexAttributePosition = 0,
VertexAttributeTexcoord = 1,
VertexAttributeColor = 2,
VertexAttributePosition = 0,
VertexAttributeTexcoord = 1,
VertexAttributeColor = 2,
};
typedef NS_ENUM(NSInteger, TextureIndex)
{
TextureIndexColor = 0,
TextureIndexColor = 0,
};
typedef NS_ENUM(NSInteger, SamplerIndex)
{
SamplerIndexDraw = 0,
SamplerIndexDraw = 0,
};
typedef struct {
typedef struct
{
vector_float3 position METAL_ATTRIBUTE(VertexAttributePosition);
vector_float2 texCoord METAL_ATTRIBUTE(VertexAttributeTexcoord);
} Vertex;
@ -68,16 +63,20 @@ typedef struct
typedef struct
{
matrix_float4x4 projectionMatrix;
matrix_float4x4 projectionMatrix;
vector_float2 outputSize;
float time;
} Uniforms;
typedef struct {
typedef struct
{
vector_float2 position METAL_ATTRIBUTE(VertexAttributePosition);
vector_float2 texCoord METAL_ATTRIBUTE(VertexAttributeTexcoord);
vector_float4 color METAL_ATTRIBUTE(VertexAttributeColor);
} FontVertex;
} SpriteVertex;
typedef struct {
typedef struct
{
vector_float4 position METAL_POSITION;
vector_float2 texCoord;
vector_float4 color;

View File

@ -36,27 +36,9 @@ fragment float4 basic_fragment_proj_tex(ColorInOut in [[stage_in]],
return float4(colorSample);
}
#pragma mark - functions using normalized device coordinates
#pragma mark - functions for rendering sprites
vertex ColorInOut basic_vertex_ndc_tex(const Vertex in [[ stage_in ]])
{
ColorInOut out;
out.position = float4(in.position, 1.0);
out.texCoord = in.texCoord;
return out;
}
fragment float4 basic_fragment_ndc_tex(ColorInOut in [[stage_in]],
texture2d<half> tex [[ texture(TextureIndexColor) ]],
sampler samp [[ sampler(SamplerIndexDraw) ]])
{
half4 colorSample = tex.sample(samp, in.texCoord.xy);
return float4(colorSample);
}
#pragma mark - functions for rendering fonts
vertex FontFragmentIn font_vertex(const FontVertex in [[ stage_in ]], const device Uniforms &uniforms [[ buffer(BufferIndexUniforms) ]])
vertex FontFragmentIn sprite_vertex(const SpriteVertex in [[ stage_in ]], const device Uniforms &uniforms [[ buffer(BufferIndexUniforms) ]])
{
FontFragmentIn out;
out.position = uniforms.projectionMatrix * float4(in.position, 0, 1);
@ -65,10 +47,67 @@ vertex FontFragmentIn font_vertex(const FontVertex in [[ stage_in ]], const devi
return out;
}
fragment float4 font_fragment(FontFragmentIn in [[ stage_in ]],
fragment float4 sprite_fragment_a8(FontFragmentIn in [[ stage_in ]],
texture2d<half> tex [[ texture(TextureIndexColor) ]],
sampler samp [[ sampler(SamplerIndexDraw) ]])
{
half4 colorSample = tex.sample(samp, in.texCoord.xy);
return float4(in.color.rgb, in.color.a * colorSample.r);
}
#pragma mark - functions for rendering sprites
vertex FontFragmentIn stock_vertex(const SpriteVertex in [[ stage_in ]], const device Uniforms &uniforms [[ buffer(BufferIndexUniforms) ]])
{
FontFragmentIn out;
out.position = uniforms.projectionMatrix * float4(in.position, 0, 1);
out.texCoord = in.texCoord;
out.color = in.color;
return out;
}
fragment float4 stock_fragment(FontFragmentIn in [[ stage_in ]],
texture2d<float> tex [[ texture(TextureIndexColor) ]],
sampler samp [[ sampler(SamplerIndexDraw) ]])
{
float4 colorSample = tex.sample(samp, in.texCoord.xy);
return colorSample * in.color;
}
#pragma mark - filter kernels
kernel void convert_bgra4444_to_bgra8888(device uint16_t * in [[ buffer(0) ]],
texture2d<half, access::write> out [[ texture(0) ]],
uint id [[ thread_position_in_grid ]])
{
uint16_t pix = in[id];
uchar4 pix2 = uchar4(
extract_bits(pix, 4, 4),
extract_bits(pix, 8, 4),
extract_bits(pix, 12, 4),
extract_bits(pix, 0, 4)
);
uint ypos = id / out.get_width();
uint xpos = id % out.get_width();
out.write(half4(pix2) / 15.0, uint2(xpos, ypos));
}
kernel void convert_rgb565_to_bgra8888(device uint16_t * in [[ buffer(0) ]],
texture2d<half, access::write> out [[ texture(0) ]],
uint id [[ thread_position_in_grid ]])
{
uint16_t pix = in[id];
uchar4 pix2 = uchar4(
extract_bits(pix, 11, 5),
extract_bits(pix, 5, 6),
extract_bits(pix, 0, 5),
0xf
);
uint ypos = id / out.get_width();
uint xpos = id % out.get_width();
out.write(half4(pix2) / half4(0x1f, 0x3f, 0x1f, 0xf), uint2(xpos, ypos));
}

View File

@ -4,9 +4,7 @@
#import "View.h"
@class Renderer;
@interface TexturedView : NSObject<View>
@interface TexturedView : NSObject
@property (readonly) RPixelFormat format;
@property (readonly) RTextureFilter filter;
@ -15,7 +13,7 @@
@property (readwrite) CGSize size;
@property (readonly) ViewDrawState drawState;
- (instancetype)initWithDescriptor:(ViewDescriptor *)td renderer:(Renderer *)renderer;
- (instancetype)initWithDescriptor:(ViewDescriptor *)td context:(Context *)c;
- (void)drawWithContext:(Context *)ctx;
- (void)drawWithEncoder:(id<MTLRenderCommandEncoder>)rce;

View File

@ -4,16 +4,13 @@
#import "TexturedView.h"
#import "RendererCommon.h"
#import "Renderer.h"
#import "View.h"
#import "Filter.h"
#import "ShaderTypes.h"
@implementation TexturedView
{
__weak Renderer *_renderer;
Context *_context;
id<MTLTexture> _texture; // optimal render texture
Vertex _v[4];
@ -25,15 +22,14 @@
bool _pixelsDirty;
}
- (instancetype)initWithDescriptor:(ViewDescriptor *)d renderer:(Renderer *)r
- (instancetype)initWithDescriptor:(ViewDescriptor *)d context:(Context *)c
{
self = [super init];
if (self) {
_renderer = r;
_format = d.format;
_bpp = RPixelFormatToBPP(_format);
_filter = d.filter;
_context = r.context;
_context = c;
_visible = YES;
if (_format == RPixelFormatBGRA8Unorm || _format == RPixelFormatBGRX8Unorm) {
_drawState = ViewDrawStateEncoder;
@ -114,7 +110,7 @@
if (!_pixelsDirty)
return;
[_renderer.conv convertFormat:_format from:_pixels to:_texture];
[_context convertFormat:_format from:_pixels to:_texture];
_pixelsDirty = NO;
}
@ -134,7 +130,7 @@
if (_format == RPixelFormatBGRA8Unorm || _format == RPixelFormatBGRX8Unorm) {
[_texture replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)_size.width, (NSUInteger)_size.height)
mipmapLevel:0 withBytes:src
bytesPerRow:(NSUInteger)(4 * _size.width)];
bytesPerRow:(NSUInteger)(4 * pitch)];
}
else {
void *dst = _pixels.contents;

View File

@ -19,21 +19,6 @@ typedef NS_ENUM(NSInteger, ViewDrawState)
ViewDrawStateAll = 0x03,
};
@protocol View<NSObject>
@property (readonly) RPixelFormat format;
@property (readonly) RTextureFilter filter;
@property (readwrite) BOOL visible;
@property (readwrite) CGRect frame;
@property (readwrite) CGSize size;
@property (readonly) ViewDrawState drawState;
@optional
- (void)drawWithContext:(Context *)ctx;
- (void)drawWithEncoder:(id<MTLRenderCommandEncoder>)rce;
@end
@interface ViewDescriptor : NSObject
@property (readwrite) RPixelFormat format;
@property (readwrite) RTextureFilter filter;

View File

@ -6,6 +6,7 @@
// Copyright © 2018 Stuart Carnie. All rights reserved.
//
#import "View.h"
#import "RendererCommon.h"
@implementation ViewDescriptor

View File

@ -6,6 +6,7 @@
//
#import "RendererCommon.h"
#import "Renderer.h"
#import "Context.h"
#import "View.h"
#import "TexturedView.h"
#import "MenuDisplay.h"

View File

@ -26,7 +26,7 @@ extern MTLPixelFormat SelectOptimalPixelFormat(MTLPixelFormat fmt);
#pragma mark - Classes
@interface FrameView : NSObject<View>
@interface FrameView : NSObject
@property (readonly) RPixelFormat format;
@property (readonly) RTextureFilter filter;
@ -35,7 +35,6 @@ extern MTLPixelFormat SelectOptimalPixelFormat(MTLPixelFormat fmt);
@property (readwrite) CGSize size;
@property (readonly) ViewDrawState drawState;
@property (readonly) struct video_shader* shader;
@property (readwrite) uint64_t frameCount;
- (void)setFilteringIndex:(int)index smooth:(bool)smooth;
@ -63,17 +62,26 @@ extern MTLPixelFormat SelectOptimalPixelFormat(MTLPixelFormat fmt);
@property (readonly) video_viewport_t* viewport;
@property (readwrite) bool keepAspect;
@property (readonly) MetalMenu* menu;
@property (readwrite) uint64_t frameCount;
@property (readonly) FrameView* frameView;
@property (readonly) MenuDisplay* display;
@property (readonly) Context* context;
@property (readonly) Uniforms* viewportMVP;
- (instancetype)init NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithVideo:(const video_info_t *)video
input:(const input_driver_t **)input
inputData:(void **)inputData;
- (void)setVideo:(const video_info_t *)video;
- (void)setShaderIndex:(NSUInteger)index;
- (bool)renderFrame:(const void *)data
width:(unsigned)width
height:(unsigned)height
frameCount:(uint64_t)frameCount
pitch:(unsigned)pitch
msg:(const char *)msg
info:(video_frame_info_t *)video_info;
- (void)beginFrame;
- (void)drawViews;
- (void)endFrame;
- (id<MTLRenderPipelineState>)getStockShader:(int)index blend:(bool)blend;
/*! @brief setNeedsResize triggers a display resize */
- (void)setNeedsResize;

File diff suppressed because it is too large Load Diff

View File

@ -50,32 +50,13 @@ static void *metal_init(const video_info_t *video,
const input_driver_t **input,
void **input_data)
{
gfx_ctx_mode_t mode;
[apple_platform setViewType:APPLE_VIEW_TYPE_METAL];
MetalDriver *md = [MetalDriver new];
if (md == nil) {
MetalDriver *md = [[MetalDriver alloc] initWithVideo:video input:input inputData:input_data];
if (md == nil)
{
return NULL;
}
MetalView *view = (MetalView *)apple_platform.renderView;
view.delegate = md;
md.keepAspect = video->force_aspect;
RARCH_LOG("[Metal]: Detecting screen resolution %ux%u.\n", video->width, video->height);
mode.width = video->width;
mode.height = video->height;
mode.fullscreen = video->fullscreen;
[md setVideo:video];
[apple_platform setVideoMode:mode];
*input = NULL;
*input_data = NULL;
font_driver_init_osd((__bridge_retained void *)md, false, video->is_threaded, FONT_DRIVER_RENDER_METAL_API);
return (__bridge_retained void *)md;
}
@ -85,42 +66,13 @@ static bool metal_frame(void *data, const void *frame,
unsigned pitch, const char *msg, video_frame_info_t *video_info)
{
MetalDriver *md = (__bridge MetalDriver *)data;
@autoreleasepool {
[md beginFrame];
FrameView *v = md.frameView;
v.frameCount = frame_count;
v.size = CGSizeMake(frame_width, frame_height);
[v updateFrame:frame pitch:pitch];
#if defined(HAVE_MENU)
if (md.menu.enabled) {
menu_driver_frame(video_info);
}
#endif
[md drawViews];
if (video_info->statistics_show)
{
struct font_params* osd_params = (struct font_params*)&video_info->osd_stat_params;
if (osd_params)
{
font_driver_render_msg(video_info, NULL, video_info->stat_text,
(const struct font_params*)&video_info->osd_stat_params);
}
}
if (msg && *msg)
{
font_driver_render_msg(video_info, NULL, msg, NULL);
}
[md endFrame];
}
return YES;
return [md renderFrame:frame
width:frame_width
height:frame_height
frameCount:frame_count
pitch:pitch
msg:msg
info:video_info];
}
static void metal_set_nonblock_state(void *data, bool state)
@ -141,7 +93,7 @@ static bool metal_suppress_screensaver(void *data, bool enable)
{
bool enabled = enable;
(void)data;
return video_context_driver_suppress_screensaver(&enabled);
}
@ -154,12 +106,13 @@ static bool metal_set_shader(void *data,
return false;
if (!path)
return true;
if (type != RARCH_SHADER_SLANG) {
if (type != RARCH_SHADER_SLANG)
{
RARCH_WARN("[Metal] Only .slang or .slangp shaders are supported. Falling back to stock.\n");
return false;
}
return [md.frameView setShaderFromPath:[NSString stringWithUTF8String:path]];
#else
return false;
@ -170,13 +123,12 @@ static void metal_free(void *data)
{
MetalDriver *md = (__bridge_transfer MetalDriver *)data;
md = nil;
font_driver_free_osd();
}
static void metal_set_viewport(void *data, unsigned viewport_width,
unsigned viewport_height, bool force_full, bool allow_rotate)
{
RARCH_LOG("[Metal]: set_viewport\n");
//RARCH_LOG("[Metal]: set_viewport %dx%d\n", viewport_width, viewport_height);
}
static void metal_set_rotation(void *data, unsigned rotation)
@ -197,12 +149,12 @@ static bool metal_read_viewport(void *data, uint8_t *buffer, bool is_idle)
#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,
// 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,
@ -218,36 +170,23 @@ static uintptr_t metal_load_texture(void *video_data, void *data,
bool threaded, enum texture_filter_type filter_type)
{
MetalDriver *md = (__bridge MetalDriver *)video_data;
struct texture_image *image = (struct texture_image *)data;
if (!image)
struct texture_image *img = (struct texture_image *)data;
if (!img)
return 0;
if (!image->pixels && !image->width && !image->height) {
/* Create a dummy texture instead. */
#define T0 0xff000000u
#define T1 0xffffffffu
static const uint32_t checkerboard[] = {
T0, T1, T0, T1, T0, T1, T0, T1,
T1, T0, T1, T0, T1, T0, T1, T0,
T0, T1, T0, T1, T0, T1, T0, T1,
T1, T0, T1, T0, T1, T0, T1, T0,
T0, T1, T0, T1, T0, T1, T0, T1,
T1, T0, T1, T0, T1, T0, T1, T0,
T0, T1, T0, T1, T0, T1, T0, T1,
T1, T0, T1, T0, T1, T0, T1, T0,
};
#undef T0
#undef T1
}
else {
}
return 0;
struct texture_image image = *img;
Texture *t = [md.context newTexture:image filter:filter_type];
return (uintptr_t)(__bridge_retained void *)(t);
}
static void metal_unload_texture(void *data, uintptr_t handle)
{
if (!handle)
{
return;
}
Texture *t = (__bridge_transfer Texture *)(void *)handle;
t = nil;
}
static void metal_set_video_mode(void *data,
@ -260,7 +199,7 @@ static void metal_set_video_mode(void *data,
.height = height,
.fullscreen = fullscreen,
};
//[md setVideoMode:mode];
}
@ -268,7 +207,7 @@ static float metal_get_refresh_rate(void *data)
{
MetalDriver *md = (__bridge MetalDriver *)data;
(void)md;
return 0.0f;
}
@ -281,27 +220,28 @@ static void metal_set_filtering(void *data, unsigned index, bool smooth)
static void metal_set_aspect_ratio(void *data, unsigned aspect_ratio_idx)
{
MetalDriver *md = (__bridge MetalDriver *)data;
switch (aspect_ratio_idx) {
switch (aspect_ratio_idx)
{
case ASPECT_RATIO_SQUARE:
video_driver_set_viewport_square_pixel();
break;
case ASPECT_RATIO_CORE:
video_driver_set_viewport_core();
break;
case ASPECT_RATIO_CONFIG:
video_driver_set_viewport_config();
break;
default:
break;
}
video_driver_set_aspect_ratio_value(
aspectratio_lut[aspect_ratio_idx].value);
md.keepAspect = YES;
[md setNeedsResize];
}
@ -318,7 +258,7 @@ static void metal_set_texture_frame(void *data, const void *frame,
{
MetalDriver *md = (__bridge MetalDriver *)data;
settings_t *settings = config_get_ptr();
[md.menu updateWidth:width
height:height
format:rgb32 ? RPixelFormatBGRA8Unorm : RPixelFormatBGRA4Unorm
@ -332,23 +272,30 @@ static void metal_set_texture_enable(void *data, bool state, bool full_screen)
MetalDriver *md = (__bridge MetalDriver *)data;
if (!md)
return;
md.menu.enabled = state;
//md.menu.fullScreen = full_screen;
}
static void metal_set_osd_msg(void *data,
video_frame_info_t *video_info,
const char *msg,
const void *params, void *font)
{
font_driver_render_msg(video_info, font, msg, (const struct font_params *)params);
}
static void metal_show_mouse(void *data, bool state)
{
[apple_platform setCursorVisible:state];
}
static struct video_shader* metal_get_current_shader(void* data)
static struct video_shader *metal_get_current_shader(void *data)
{
MetalDriver *md = (__bridge MetalDriver *)data;
if (!md)
return NULL;
return md.frameView.shader;
}
@ -356,11 +303,11 @@ static struct video_shader* metal_get_current_shader(void* data)
static uint32_t metal_get_flags(void *data)
{
uint32_t flags = 0;
BIT32_SET(flags, GFX_CTX_FLAGS_CUSTOMIZABLE_SWAPCHAIN_IMAGES);
BIT32_SET(flags, GFX_CTX_FLAGS_BLACK_FRAME_INSERTION);
BIT32_SET(flags, GFX_CTX_FLAGS_MENU_FRAME_FILTERING);
return flags;
}
@ -375,6 +322,7 @@ static const video_poke_interface_t metal_poke_interface = {
.apply_state_changes = metal_apply_state_changes,
.set_texture_frame = metal_set_texture_frame,
.set_texture_enable = metal_set_texture_enable,
.set_osd_msg = metal_set_osd_msg,
.show_mouse = metal_show_mouse,
.get_current_shader = metal_get_current_shader,
};

View File

@ -40,10 +40,12 @@
Uniforms _uniforms;
id<MTLBuffer> _vert;
unsigned _capacity;
unsigned _offset;
unsigned _vertices;
}
@property (readwrite) MetalDriver *metal;
@property (weak, readwrite) MetalDriver *metal;
@property (readonly) struct font_atlas *atlas;
@property (readwrite) bool needsUpdate;
@ -55,26 +57,54 @@
@implementation MetalRaster
/* macOS requires constants in a buffer to have a 256 byte alignment. */
#ifdef TARGET_OS_MAC
static const NSUInteger kConstantAlignment = 256;
#else
static const NSUInteger kConstantAlignment = 4;
#endif
#define ALIGN_CONSTANTS(size) ((size + kConstantAlignment - 1) & (~(kConstantAlignment - 1)))
- (instancetype)initWithDriver:(MetalDriver *)metal fontPath:(const char *)font_path fontSize:(unsigned)font_size
{
if (self = [super init]) {
if (self = [super init])
{
if (metal == nil)
return nil;
_metal = metal;
_context = metal.context;
if (!font_renderer_create_default((const void **)&_font_driver,
&_font_data, font_path, font_size)) {
&_font_data, font_path, font_size))
{
RARCH_WARN("Couldn't initialize font renderer.\n");
return nil;
}
_uniforms.projectionMatrix = matrix_proj_ortho(0, 1, 0, 1);
_atlas = _font_driver->get_atlas(_font_data);
_stride = _atlas->width;
_buffer = [_context.device newBufferWithBytes:_atlas->buffer
length:(NSUInteger)(_atlas->width * _atlas->height)
options:MTLResourceStorageModeManaged];
_stride = ALIGN_CONSTANTS(_atlas->width);
if (_stride == _atlas->width)
{
_buffer = [_context.device newBufferWithBytes:_atlas->buffer
length:(NSUInteger)(_stride * _atlas->height)
options:MTLResourceStorageModeManaged];
}
else
{
_buffer = [_context.device newBufferWithLength:(NSUInteger)(_stride * _atlas->height)
options:MTLResourceStorageModeManaged];
void *dst = _buffer.contents;
void *src = _atlas->buffer;
for (unsigned i = 0; i < _atlas->height; i++)
{
memcpy(dst, src, _atlas->width);
dst += _stride;
src += _atlas->width;
}
[_buffer didModifyRange:NSMakeRange(0, _buffer.length)];
}
MTLTextureDescriptor *td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Unorm
width:_atlas->width
@ -83,9 +113,12 @@
_texture = [_buffer newTextureWithDescriptor:td offset:0 bytesPerRow:_stride];
_vert = [_context.device newBufferWithLength:sizeof(FontVertex) * 500 options:MTLResourceStorageModeManaged];
_capacity = 12000;
_vert = [_context.device newBufferWithLength:sizeof(SpriteVertex) *
_capacity options:MTLResourceStorageModeManaged];
_needsUpdate = true;
if (![self _initializeState]) {
if (![self _initializeState])
{
return nil;
}
}
@ -98,11 +131,11 @@
MTLVertexDescriptor *vd = [MTLVertexDescriptor new];
vd.attributes[0].offset = 0;
vd.attributes[0].format = MTLVertexFormatFloat2;
vd.attributes[1].offset = offsetof(FontVertex, texCoord);
vd.attributes[1].offset = offsetof(SpriteVertex, texCoord);
vd.attributes[1].format = MTLVertexFormatFloat2;
vd.attributes[2].offset = offsetof(FontVertex, color);
vd.attributes[2].offset = offsetof(SpriteVertex, color);
vd.attributes[2].format = MTLVertexFormatFloat4;
vd.layouts[0].stride = sizeof(FontVertex);
vd.layouts[0].stride = sizeof(SpriteVertex);
vd.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
MTLRenderPipelineDescriptor *psd = [MTLRenderPipelineDescriptor new];
@ -118,12 +151,13 @@
psd.sampleCount = 1;
psd.vertexDescriptor = vd;
psd.vertexFunction = [_context.library newFunctionWithName:@"font_vertex"];
psd.fragmentFunction = [_context.library newFunctionWithName:@"font_fragment"];
psd.vertexFunction = [_context.library newFunctionWithName:@"sprite_vertex"];
psd.fragmentFunction = [_context.library newFunctionWithName:@"sprite_fragment_a8"];
NSError *err;
_state = [_context.device newRenderPipelineStateWithDescriptor:psd error:&err];
if (err != nil) {
if (err != nil)
{
RARCH_ERR("[MetalRaster]: error creating pipeline state: %s\n", err.localizedDescription.UTF8String);
return NO;
}
@ -146,9 +180,11 @@
- (void)updateGlyph:(const struct font_glyph *)glyph
{
if (_atlas->dirty) {
if (_atlas->dirty)
{
unsigned row;
for (row = glyph->atlas_offset_y; row < (glyph->atlas_offset_y + glyph->height); row++) {
for (row = glyph->atlas_offset_y; row < (glyph->atlas_offset_y + glyph->height); row++)
{
uint8_t *src = _atlas->buffer + row * _atlas->width + glyph->atlas_offset_x;
uint8_t *dst = (uint8_t *)_buffer.contents + row * _stride + glyph->atlas_offset_x;
memcpy(dst, src, glyph->width);
@ -167,19 +203,21 @@
{
int delta_x = 0;
for (unsigned i = 0; i < length; i++) {
for (unsigned i = 0; i < length; i++)
{
const struct font_glyph *glyph = _font_driver->get_glyph(_font_data, (uint8_t)msg[i]);
if (!glyph) /* Do something smarter here ... */
glyph = _font_driver->get_glyph(_font_data, '?');
if (glyph) {
if (glyph)
{
[self updateGlyph:glyph];
delta_x += glyph->advance_x;
}
}
return delta_x * scale;
return (int)(delta_x * scale);
}
- (const struct font_glyph *)getGlyph:(uint32_t)code
@ -188,22 +226,18 @@
return NULL;
const struct font_glyph *glyph = _font_driver->get_glyph((void *)_font_driver, code);
if (glyph) {
if (glyph)
{
[self updateGlyph:glyph];
}
return glyph;
}
typedef struct color
{
float r, g, b, a;
} color_t;
static INLINE void write_quad(FontVertex *pv,
float x, float y, float width, float height,
float tex_x, float tex_y, float tex_width, float tex_height,
const vector_float4 *color)
static INLINE void write_quad6(SpriteVertex *pv,
float x, float y, float width, float height,
float tex_x, float tex_y, float tex_width, float tex_height,
const vector_float4 *color)
{
unsigned i;
static const float strip[2 * 6] = {
@ -215,11 +249,12 @@ static INLINE void write_quad(FontVertex *pv,
0.0f, 1.0f,
};
for (i = 0; i < 6; i++) {
pv[i].position.x = x + strip[2 * i + 0] * width;
pv[i].position.y = y + strip[2 * i + 1] * height;
pv[i].texCoord.x = tex_x + strip[2 * i + 0] * tex_width;
pv[i].texCoord.y = tex_y + strip[2 * i + 1] * tex_height;
for (i = 0; i < 6; i++)
{
pv[i].position = simd_make_float2(x + strip[2 * i + 0] * width,
y + strip[2 * i + 1] * height);
pv[i].texCoord = simd_make_float2(tex_x + strip[2 * i + 0] * tex_width,
tex_y + strip[2 * i + 1] * tex_height);
pv[i].color = *color;
}
}
@ -233,33 +268,36 @@ static INLINE void write_quad(FontVertex *pv,
posY:(float)posY
aligned:(unsigned)aligned
{
const char* msg_end = msg + length;
int x = roundf(posX * _metal.viewport->width);
int y = roundf((1.0f - posY) * _metal.viewport->height);
int delta_x = 0;
int delta_y = 0;
const char *msg_end = msg + length;
int x = roundf(posX * _metal.viewport->width);
int y = roundf((1.0f - posY) * _metal.viewport->height);
int delta_x = 0;
int delta_y = 0;
float inv_tex_size_x = 1.0f / _texture.width;
float inv_tex_size_y = 1.0f / _texture.height;
float inv_win_width = 1.0f / _metal.viewport->width;
float inv_win_width = 1.0f / _metal.viewport->width;
float inv_win_height = 1.0f / _metal.viewport->height;
switch (aligned) {
switch (aligned)
{
case TEXT_ALIGN_RIGHT:
x -= [self getWidthForMessage:msg length:length scale:scale];
break;
case TEXT_ALIGN_CENTER:
x -= [self getWidthForMessage:msg length:length scale:scale] / 2;
break;
default:
break;
}
FontVertex *v = (FontVertex *)_vert.contents;
SpriteVertex *v = (SpriteVertex *)_vert.contents;
v += _offset + _vertices;
while (msg < msg_end) {
unsigned code = utf8_walk(&msg);
while (msg < msg_end)
{
unsigned code = utf8_walk(&msg);
const struct font_glyph *glyph = _font_driver->get_glyph(_font_data, code);
if (!glyph) /* Do something smarter here ... */
@ -271,33 +309,36 @@ static INLINE void write_quad(FontVertex *pv,
[self updateGlyph:glyph];
int off_x, off_y, tex_x, tex_y, width, height;
off_x = glyph->draw_offset_x;
off_y = glyph->draw_offset_y;
tex_x = glyph->atlas_offset_x;
tex_y = glyph->atlas_offset_y;
width = glyph->width;
off_x = glyph->draw_offset_x;
off_y = glyph->draw_offset_y;
tex_x = glyph->atlas_offset_x;
tex_y = glyph->atlas_offset_y;
width = glyph->width;
height = glyph->height;
write_quad(v + _vertices,
(x + off_x + delta_x * scale) * inv_win_width,
(y + off_y + delta_y * scale) * inv_win_height,
width * scale * inv_win_width,
height * scale * inv_win_height,
tex_x * inv_tex_size_x,
tex_y * inv_tex_size_y,
width * inv_tex_size_x,
height * inv_tex_size_y,
&color);
write_quad6(v,
(x + off_x + delta_x * scale) * inv_win_width,
(y + off_y + delta_y * scale) * inv_win_height,
width * scale * inv_win_width,
height * scale * inv_win_height,
tex_x * inv_tex_size_x,
tex_y * inv_tex_size_y,
width * inv_tex_size_x,
height * inv_tex_size_y,
&color);
_vertices += 6;
v += 6;
delta_x += glyph->advance_x;
delta_y += glyph->advance_y;
delta_x += glyph->advance_x;
delta_y += glyph->advance_y;
}
}
- (void)_flush {
[_vert didModifyRange:NSMakeRange(0, sizeof(FontVertex)*_vertices)];
- (void)_flush
{
NSUInteger start = _offset * sizeof(SpriteVertex);
[_vert didModifyRange:NSMakeRange(start, sizeof(SpriteVertex) * _vertices)];
_rpd.colorAttachments[0].texture = _context.nextDrawable.texture;
id<MTLCommandBuffer> cb = _context.commandBuffer;
@ -305,12 +346,14 @@ static INLINE void write_quad(FontVertex *pv,
[rce pushDebugGroup:@"render fonts"];
[rce setRenderPipelineState:_state];
[rce setVertexBytes:&_uniforms length:sizeof(_uniforms) atIndex:BufferIndexUniforms];
[rce setVertexBuffer:_vert offset:0 atIndex:BufferIndexPositions];
[rce setVertexBuffer:_vert offset:start atIndex:BufferIndexPositions];
[rce setFragmentTexture:_texture atIndex:TextureIndexColor];
[rce setFragmentSamplerState:_sampler atIndex:SamplerIndexDraw];
[rce drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:_vertices];
[rce popDebugGroup];
[rce endEncoding];
_offset += _vertices;
_vertices = 0;
}
@ -323,7 +366,8 @@ static INLINE void write_quad(FontVertex *pv,
aligned:(unsigned)aligned
{
/* If the font height is not supported just draw as usual */
if (!_font_driver->get_line_height) {
if (!_font_driver->get_line_height)
{
[self _renderLine:msg video:video length:strlen(msg) scale:scale color:color posX:posX posY:posY aligned:aligned];
return;
}
@ -331,11 +375,13 @@ static INLINE void write_quad(FontVertex *pv,
int lines = 0;
float line_height = _font_driver->get_line_height(_font_data) * scale / video->height;
for (;;) {
for (;;)
{
const char *delim = strchr(msg, '\n');
/* Draw the line */
if (delim) {
if (delim)
{
unsigned msg_len = delim - msg;
[self _renderLine:msg
video:video
@ -348,7 +394,8 @@ static INLINE void write_quad(FontVertex *pv,
msg += msg_len + 1;
lines++;
}
else {
else
{
unsigned msg_len = strlen(msg);
[self _renderLine:msg
video:video
@ -378,7 +425,8 @@ static INLINE void write_quad(FontVertex *pv,
unsigned width = video->width;
unsigned height = video->height;
if (params) {
if (params)
{
x = params->x;
y = params->y;
scale = params->scale;
@ -387,21 +435,26 @@ static INLINE void write_quad(FontVertex *pv,
drop_y = params->drop_y;
drop_mod = params->drop_mod;
drop_alpha = params->drop_alpha;
color.x = FONT_COLOR_GET_RED(params->color) / 255.0f;
color.y = FONT_COLOR_GET_GREEN(params->color) / 255.0f;
color.z = FONT_COLOR_GET_BLUE(params->color) / 255.0f;
color.w = FONT_COLOR_GET_ALPHA(params->color) / 255.0f;
color = simd_make_float4(
FONT_COLOR_GET_RED(params->color) / 255.0f,
FONT_COLOR_GET_GREEN(params->color) / 255.0f,
FONT_COLOR_GET_BLUE(params->color) / 255.0f,
FONT_COLOR_GET_ALPHA(params->color) / 255.0f);
}
else {
else
{
x = video->font_msg_pos_x;
y = video->font_msg_pos_y;
scale = 1.0f;
text_align = TEXT_ALIGN_LEFT;
color.x = video->font_msg_color_r;
color.y = video->font_msg_color_g;
color.z = video->font_msg_color_b;
color.w = 1.0;
color = simd_make_float4(
video->font_msg_color_r,
video->font_msg_color_g,
video->font_msg_color_b,
1.0f);
drop_x = -2;
drop_y = -2;
@ -409,19 +462,20 @@ static INLINE void write_quad(FontVertex *pv,
drop_alpha = 1.0f;
}
@autoreleasepool {
@autoreleasepool
{
NSUInteger max_glyphs = strlen(msg);
if (drop_x || drop_y)
max_glyphs *= 2;
NSUInteger needed = sizeof(FontVertex) * max_glyphs * 6;
if (_vert.length < needed)
if (max_glyphs * 6 + _offset > _capacity)
{
_vert = [_context.device newBufferWithLength:needed options:MTLResourceStorageModeManaged];
_offset = 0;
}
if (drop_x || drop_y) {
if (drop_x || drop_y)
{
color_dark.x = color.x * drop_mod;
color_dark.y = color.y * drop_mod;
color_dark.z = color.z * drop_mod;
@ -456,7 +510,7 @@ static void *metal_raster_font_init_font(void *data,
const char *font_path, float font_size,
bool is_threaded)
{
MetalRaster *r = [[MetalRaster alloc] initWithDriver:(__bridge_transfer MetalDriver *)data fontPath:font_path fontSize:(unsigned)font_size];
MetalRaster *r = [[MetalRaster alloc] initWithDriver:(__bridge MetalDriver *)data fontPath:font_path fontSize:(unsigned)font_size];
if (!r)
return NULL;
@ -478,16 +532,16 @@ static int metal_get_message_width(void *data, const char *msg,
}
static void metal_raster_font_render_msg(
video_frame_info_t *video_info,
void *data, const char *msg,
const struct font_params *params)
video_frame_info_t *video_info,
void *data, const char *msg,
const struct font_params *params)
{
MetalRaster *r = (__bridge MetalRaster *)data;
[r renderMessage:msg video:video_info params:params];
}
static const struct font_glyph *metal_raster_font_get_glyph(
void *data, uint32_t code)
void *data, uint32_t code)
{
MetalRaster *r = (__bridge MetalRaster *)data;
return [r getGlyph:code];

View File

@ -60,11 +60,10 @@
#ifdef HAVE_METAL
#import "../gfx/common/metal/Context.m"
#import "../gfx/common/metal/Filter.m"
#import "../gfx/common/metal/PixelConverter.m"
#import "../gfx/common/metal/Renderer.m"
#import "../gfx/common/metal/RendererCommon.m"
#import "../gfx/common/metal/View.m"
#import "../gfx/common/metal/TexturedView.m"
#import "../gfx/common/metal/MenuDisplay.m"
#import "../gfx/common/metal_common.m"
#import "../gfx/drivers/metal.m"
#import "../menu/drivers_display/menu_display_metal.m"

View File

@ -17,31 +17,60 @@
#include "../../gfx/video_driver.h"
#import "../../gfx/common/metal_common.h"
#define GET_DRIVER(video_info) (video_info ? (__bridge MetalDriver *)video_info->userdata : NULL);
static const float *menu_display_metal_get_default_vertices(void)
{
return [MenuDisplay defaultVertices];
}
static const float *menu_display_metal_get_default_tex_coords(void)
{
return [MenuDisplay defaultTexCoords];
}
static void *menu_display_metal_get_default_mvp(video_frame_info_t *video_info)
{
return NULL;
MetalDriver *md = GET_DRIVER(video_info);
if (!md)
return NULL;
return (void *)md.viewportMVP;
}
static void menu_display_metal_blend_begin(video_frame_info_t *video_info)
{
MetalDriver *md = GET_DRIVER(video_info);
if (!md)
return;
md.display.blend = YES;
}
static void menu_display_metal_blend_end(video_frame_info_t *video_info)
{
MetalDriver *md = GET_DRIVER(video_info);
if (!md)
return;
md.display.blend = NO;
}
static void menu_display_metal_draw(menu_display_ctx_draw_t *draw,
video_frame_info_t *video_info)
video_frame_info_t *video_info)
{
MetalDriver *md = GET_DRIVER(video_info);
if (!md || !draw)
return;
[md.display draw:draw video:video_info];
}
static void menu_display_metal_draw_pipeline(
menu_display_ctx_draw_t *draw, video_frame_info_t *video_info)
static void menu_display_metal_draw_pipeline(menu_display_ctx_draw_t *draw, video_frame_info_t *video_info)
{
}
static void menu_display_metal_viewport(menu_display_ctx_draw_t *draw,
video_frame_info_t *video_info)
video_frame_info_t *video_info)
{
}
@ -49,56 +78,47 @@ static void menu_display_metal_restore_clear_color(void)
{
}
static void menu_display_metal_clear_color(
menu_display_ctx_clearcolor_t *clearcolor,
video_frame_info_t *video_info)
static void menu_display_metal_clear_color(menu_display_ctx_clearcolor_t *clearcolor,
video_frame_info_t *video_info)
{
(void)clearcolor;
MetalDriver *md = GET_DRIVER(video_info);
if (!md)
return;
md.display.clearColor = MTLClearColorMake(clearcolor->r, clearcolor->g, clearcolor->b, clearcolor->a);
}
static bool menu_display_metal_font_init_first(
void **font_handle, void *video_data,
const char *font_path, float font_size,
bool is_threaded)
void **font_handle, void *video_data,
const char *font_path, float font_size,
bool is_threaded)
{
font_data_t **handle = (font_data_t**)font_handle;
font_data_t **handle = (font_data_t **)font_handle;
*handle = font_driver_init_first(video_data,
font_path, font_size, true,
is_threaded,
FONT_DRIVER_RENDER_METAL_API);
if (*handle)
return true;
return false;
}
static const float *menu_display_metal_get_default_vertices(void)
{
static float dummy[16] = {0.0f};
return &dummy[0];
}
static const float *menu_display_metal_get_default_tex_coords(void)
{
static float dummy[16] = {0.0f};
return &dummy[0];
}
menu_display_ctx_driver_t menu_display_ctx_metal = {
menu_display_metal_draw,
menu_display_metal_draw_pipeline,
menu_display_metal_viewport,
menu_display_metal_blend_begin,
menu_display_metal_blend_end,
menu_display_metal_restore_clear_color,
menu_display_metal_clear_color,
menu_display_metal_get_default_mvp,
menu_display_metal_get_default_vertices,
menu_display_metal_get_default_tex_coords,
menu_display_metal_font_init_first,
MENU_VIDEO_DRIVER_GENERIC,
"menu_display_metal",
false
.draw = menu_display_metal_draw,
.draw_pipeline = menu_display_metal_draw_pipeline,
.viewport = menu_display_metal_viewport,
.blend_begin = menu_display_metal_blend_begin,
.blend_end = menu_display_metal_blend_end,
.restore_clear_color = menu_display_metal_restore_clear_color,
.clear_color = menu_display_metal_clear_color,
.get_default_mvp = menu_display_metal_get_default_mvp,
.get_default_vertices = menu_display_metal_get_default_vertices,
.get_default_tex_coords = menu_display_metal_get_default_tex_coords,
.font_init_first = menu_display_metal_font_init_first,
.type = MENU_VIDEO_DRIVER_METAL,
.ident = "menu_display_metal",
.handles_transform = NO,
};

View File

@ -9,7 +9,6 @@
/* Begin PBXBuildFile section */
05269A6220ABF20500C29F1E /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05269A6120ABF20500C29F1E /* MetalKit.framework */; };
05A8C7B420DB75A500FF7857 /* Shaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = 05A8C74E20DB72F100FF7857 /* Shaders.metal */; };
05A8C7B520DB75A800FF7857 /* PixelConverter.metal in Sources */ = {isa = PBXBuildFile; fileRef = 05A8C75920DB72F100FF7857 /* PixelConverter.metal */; };
05A8E23820A63CB40084ABDA /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05A8E23720A63CB40084ABDA /* Metal.framework */; };
05A8E23A20A63CED0084ABDA /* IOSurface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05A8E23920A63CED0084ABDA /* IOSurface.framework */; };
05A8E23C20A63CF50084ABDA /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05A8E23B20A63CF50084ABDA /* QuartzCore.framework */; };
@ -60,6 +59,17 @@
055312AE20DE130A00C4D7F4 /* pixconv.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pixconv.c; sourceTree = "<group>"; };
055312AF20DE130A00C4D7F4 /* scaler_filter.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = scaler_filter.c; sourceTree = "<group>"; };
055312B020DE130A00C4D7F4 /* scaler.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = scaler.c; sourceTree = "<group>"; };
0566C78420E49E6800BC768F /* video_frame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = video_frame.h; sourceTree = "<group>"; };
0566C78620E49E6800BC768F /* vector_4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vector_4.h; sourceTree = "<group>"; };
0566C78720E49E6800BC768F /* vector_3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vector_3.h; sourceTree = "<group>"; };
0566C78820E49E6800BC768F /* vector_2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vector_2.h; sourceTree = "<group>"; };
0566C78920E49E6800BC768F /* matrix_3x3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = matrix_3x3.h; sourceTree = "<group>"; };
0566C78A20E49E6800BC768F /* matrix_4x4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = matrix_4x4.h; sourceTree = "<group>"; };
0566C78C20E49E6800BC768F /* scaler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scaler.h; sourceTree = "<group>"; };
0566C78D20E49E6800BC768F /* pixconv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pixconv.h; sourceTree = "<group>"; };
0566C78E20E49E6800BC768F /* scaler_int.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scaler_int.h; sourceTree = "<group>"; };
0566C78F20E49E6800BC768F /* filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filter.h; sourceTree = "<group>"; };
0566C79020E49E6800BC768F /* gl_capabilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gl_capabilities.h; sourceTree = "<group>"; };
05A8C51B20DB72F000FF7857 /* menu_shader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = menu_shader.h; sourceTree = "<group>"; };
05A8C51D20DB72F000FF7857 /* menu_cbs_get_value.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = menu_cbs_get_value.c; sourceTree = "<group>"; };
05A8C51E20DB72F000FF7857 /* menu_cbs_sublabel.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = menu_cbs_sublabel.c; sourceTree = "<group>"; };
@ -279,26 +289,19 @@
05A8C73920DB72F100FF7857 /* font_driver.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = font_driver.c; sourceTree = "<group>"; };
05A8C73C20DB72F100FF7857 /* vulkan_common.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vulkan_common.c; sourceTree = "<group>"; };
05A8C74420DB72F100FF7857 /* metal_common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = metal_common.h; sourceTree = "<group>"; };
05A8C74620DB72F100FF7857 /* MetalRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MetalRenderer.h; sourceTree = "<group>"; };
05A8C74720DB72F100FF7857 /* PixelConverter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PixelConverter.h; sourceTree = "<group>"; };
05A8C74820DB72F100FF7857 /* metal_common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = metal_common.h; sourceTree = "<group>"; };
05A8C74920DB72F100FF7857 /* TexturedView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TexturedView.h; sourceTree = "<group>"; };
05A8C74A20DB72F100FF7857 /* Renderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Renderer.h; sourceTree = "<group>"; };
05A8C74B20DB72F100FF7857 /* Context.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Context.h; sourceTree = "<group>"; };
05A8C74C20DB72F100FF7857 /* RendererCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RendererCommon.h; sourceTree = "<group>"; };
05A8C74D20DB72F100FF7857 /* PixelConverter+private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PixelConverter+private.h"; sourceTree = "<group>"; };
05A8C74E20DB72F100FF7857 /* Shaders.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Shaders.metal; sourceTree = "<group>"; };
05A8C74F20DB72F100FF7857 /* View.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = View.h; sourceTree = "<group>"; };
05A8C75020DB72F100FF7857 /* Filter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Filter.m; sourceTree = "<group>"; };
05A8C75120DB72F100FF7857 /* ShaderTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ShaderTypes.h; sourceTree = "<group>"; };
05A8C75220DB72F100FF7857 /* PixelConverter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PixelConverter.m; sourceTree = "<group>"; };
05A8C75320DB72F100FF7857 /* Context.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Context.m; sourceTree = "<group>"; };
05A8C75420DB72F100FF7857 /* RendererCommon.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RendererCommon.m; sourceTree = "<group>"; };
05A8C75520DB72F100FF7857 /* Renderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Renderer.m; sourceTree = "<group>"; };
05A8C75620DB72F100FF7857 /* TexturedView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TexturedView.m; sourceTree = "<group>"; };
05A8C75720DB72F100FF7857 /* Filter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Filter.h; sourceTree = "<group>"; };
05A8C75820DB72F100FF7857 /* View.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = View.m; sourceTree = "<group>"; };
05A8C75920DB72F100FF7857 /* PixelConverter.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = PixelConverter.metal; sourceTree = "<group>"; };
05A8C75D20DB72F100FF7857 /* gl_common.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = gl_common.c; sourceTree = "<group>"; };
05A8C75E20DB72F100FF7857 /* d3d_common.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = d3d_common.c; sourceTree = "<group>"; };
05A8C76320DB72F100FF7857 /* d3d10_common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = d3d10_common.h; sourceTree = "<group>"; };
@ -352,6 +355,59 @@
05A8E23720A63CB40084ABDA /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
05A8E23920A63CED0084ABDA /* IOSurface.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOSurface.framework; path = System/Library/Frameworks/IOSurface.framework; sourceTree = SDKROOT; };
05A8E23B20A63CF50084ABDA /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
05C5D53320E3DD0900654EE4 /* input_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = input_types.h; sourceTree = "<group>"; };
05C5D53420E3DD0900654EE4 /* input_remote.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = input_remote.c; sourceTree = "<group>"; };
05C5D53720E3DD0900654EE4 /* nullinput.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nullinput.c; sourceTree = "<group>"; };
05C5D53820E3DD0900654EE4 /* cocoa_input.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cocoa_input.h; sourceTree = "<group>"; };
05C5D54120E3DD0900654EE4 /* sdl_input.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sdl_input.c; sourceTree = "<group>"; };
05C5D54220E3DD0900654EE4 /* cocoa_input.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = cocoa_input.c; sourceTree = "<group>"; };
05C5D54C20E3DD0900654EE4 /* input_keymaps.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = input_keymaps.h; sourceTree = "<group>"; };
05C5D54E20E3DD0900654EE4 /* blissbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = blissbox.h; sourceTree = "<group>"; };
05C5D55420E3DD0900654EE4 /* GCExtendedGamepadSnapshot.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GCExtendedGamepadSnapshot.h; sourceTree = "<group>"; };
05C5D55520E3DD0900654EE4 /* GCControllerButtonInput.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GCControllerButtonInput.h; sourceTree = "<group>"; };
05C5D55620E3DD0900654EE4 /* GCGamepad.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GCGamepad.h; sourceTree = "<group>"; };
05C5D55720E3DD0900654EE4 /* GCExtendedGamepad.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GCExtendedGamepad.h; sourceTree = "<group>"; };
05C5D55820E3DD0900654EE4 /* GCGamepadSnapshot.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GCGamepadSnapshot.h; sourceTree = "<group>"; };
05C5D55920E3DD0900654EE4 /* GCControllerAxisInput.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GCControllerAxisInput.h; sourceTree = "<group>"; };
05C5D55A20E3DD0900654EE4 /* GCControllerDirectionPad.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GCControllerDirectionPad.h; sourceTree = "<group>"; };
05C5D55B20E3DD0900654EE4 /* GameController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GameController.h; sourceTree = "<group>"; };
05C5D55C20E3DD0900654EE4 /* GCController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GCController.h; sourceTree = "<group>"; };
05C5D55D20E3DD0900654EE4 /* GCControllerElement.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GCControllerElement.h; sourceTree = "<group>"; };
05C5D55E20E3DD0900654EE4 /* hid_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = hid_types.h; sourceTree = "<group>"; };
05C5D55F20E3DD0900654EE4 /* hid_driver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = hid_driver.h; sourceTree = "<group>"; };
05C5D56020E3DD0900654EE4 /* gamepad.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = gamepad.h; sourceTree = "<group>"; };
05C5D56120E3DD0900654EE4 /* input_driver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = input_driver.h; sourceTree = "<group>"; };
05C5D56320E3DD0900654EE4 /* keyboard_event_apple.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = keyboard_event_apple.c; sourceTree = "<group>"; };
05C5D56620E3DD0900654EE4 /* keyboard_event_apple.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = keyboard_event_apple.h; sourceTree = "<group>"; };
05C5D56A20E3DD0900654EE4 /* input_remapping.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = input_remapping.h; sourceTree = "<group>"; };
05C5D56B20E3DD0900654EE4 /* input_mapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = input_mapper.h; sourceTree = "<group>"; };
05C5D56C20E3DD0900654EE4 /* input_overlay.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = input_overlay.h; sourceTree = "<group>"; };
05C5D56D20E3DD0900654EE4 /* input_defines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = input_defines.h; sourceTree = "<group>"; };
05C5D56F20E3DD0900654EE4 /* btstack_hid.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = btstack_hid.c; sourceTree = "<group>"; };
05C5D57020E3DD0900654EE4 /* null_hid.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = null_hid.c; sourceTree = "<group>"; };
05C5D57320E3DD0900654EE4 /* iohidmanager_hid.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = iohidmanager_hid.c; sourceTree = "<group>"; };
05C5D57620E3DD0900654EE4 /* input_common.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = input_common.c; sourceTree = "<group>"; };
05C5D57720E3DD0900654EE4 /* input_x11_common.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = input_x11_common.c; sourceTree = "<group>"; };
05C5D57820E3DD0900654EE4 /* linux_common.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = linux_common.c; sourceTree = "<group>"; };
05C5D57A20E3DD0900654EE4 /* hid_device_driver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = hid_device_driver.h; sourceTree = "<group>"; };
05C5D57B20E3DD0900654EE4 /* device_ds3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = device_ds3.c; sourceTree = "<group>"; };
05C5D57C20E3DD0900654EE4 /* device_ds4.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = device_ds4.c; sourceTree = "<group>"; };
05C5D57D20E3DD0900654EE4 /* hid_device_driver.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = hid_device_driver.c; sourceTree = "<group>"; };
05C5D57E20E3DD0900654EE4 /* device_wiiu_gca.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = device_wiiu_gca.c; sourceTree = "<group>"; };
05C5D57F20E3DD0900654EE4 /* device_null.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = device_null.c; sourceTree = "<group>"; };
05C5D58020E3DD0900654EE4 /* linux_common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = linux_common.h; sourceTree = "<group>"; };
05C5D58120E3DD0900654EE4 /* input_x11_common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = input_x11_common.h; sourceTree = "<group>"; };
05C5D58220E3DD0900654EE4 /* input_autodetect_builtin.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = input_autodetect_builtin.c; sourceTree = "<group>"; };
05C5D58320E3DD0900654EE4 /* input_keymaps.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = input_keymaps.c; sourceTree = "<group>"; };
05C5D58720E3DD0900654EE4 /* sdl_joypad.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sdl_joypad.c; sourceTree = "<group>"; };
05C5D58820E3DD0900654EE4 /* null_joypad.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = null_joypad.c; sourceTree = "<group>"; };
05C5D58D20E3DD0900654EE4 /* mfi_joypad.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = mfi_joypad.m; sourceTree = "<group>"; };
05C5D59820E3DD0A00654EE4 /* hid_joypad.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = hid_joypad.c; sourceTree = "<group>"; };
05C5D59F20E3DD0A00654EE4 /* input_remote.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = input_remote.h; sourceTree = "<group>"; };
05C5D5A020E3DD0A00654EE4 /* input_overlay.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = input_overlay.c; sourceTree = "<group>"; };
05C5D5A120E3DD0A00654EE4 /* input_mapper.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = input_mapper.c; sourceTree = "<group>"; };
05C5D5A220E3DD0A00654EE4 /* input_remapping.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = input_remapping.c; sourceTree = "<group>"; };
05C5D5A320E3DD0A00654EE4 /* input_driver.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = input_driver.c; sourceTree = "<group>"; };
05D7753120A55D2700646447 /* BaseConfig.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = BaseConfig.xcconfig; sourceTree = "<group>"; };
05D7753320A5678300646447 /* griffin_cpp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = griffin_cpp.cpp; path = ../../griffin/griffin_cpp.cpp; sourceTree = "<group>"; };
05D7753420A5678400646447 /* griffin_glslang.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = griffin_glslang.cpp; path = ../../griffin/griffin_glslang.cpp; sourceTree = "<group>"; };
@ -373,6 +429,8 @@
84DD5EB71A89F1C7007336C1 /* retroarch.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = retroarch.icns; path = ../../media/retroarch.icns; sourceTree = "<group>"; };
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = OSX/Info.plist; sourceTree = "<group>"; };
8D1107320486CEB800E47090 /* RetroArch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RetroArch.app; sourceTree = BUILT_PRODUCTS_DIR; };
A902040DE66D42F9EE47BFE3 /* MenuDisplay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MenuDisplay.h; sourceTree = "<group>"; };
A902070F2C43F222FD56A95A /* MenuDisplay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MenuDisplay.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -410,6 +468,7 @@
0538875020DE11A800769232 /* include */ = {
isa = PBXGroup;
children = (
0566C78320E49E6800BC768F /* gfx */,
0538875920DE11D300769232 /* libretro.h */,
0538875720DE11D300769232 /* retro_assert.h */,
0538875120DE11D200769232 /* retro_common_api.h */,
@ -443,6 +502,40 @@
path = scaler;
sourceTree = "<group>";
};
0566C78320E49E6800BC768F /* gfx */ = {
isa = PBXGroup;
children = (
0566C78520E49E6800BC768F /* math */,
0566C78B20E49E6800BC768F /* scaler */,
0566C78420E49E6800BC768F /* video_frame.h */,
0566C79020E49E6800BC768F /* gl_capabilities.h */,
);
path = gfx;
sourceTree = "<group>";
};
0566C78520E49E6800BC768F /* math */ = {
isa = PBXGroup;
children = (
0566C78620E49E6800BC768F /* vector_4.h */,
0566C78720E49E6800BC768F /* vector_3.h */,
0566C78820E49E6800BC768F /* vector_2.h */,
0566C78920E49E6800BC768F /* matrix_3x3.h */,
0566C78A20E49E6800BC768F /* matrix_4x4.h */,
);
path = math;
sourceTree = "<group>";
};
0566C78B20E49E6800BC768F /* scaler */ = {
isa = PBXGroup;
children = (
0566C78C20E49E6800BC768F /* scaler.h */,
0566C78D20E49E6800BC768F /* pixconv.h */,
0566C78E20E49E6800BC768F /* scaler_int.h */,
0566C78F20E49E6800BC768F /* filter.h */,
);
path = scaler;
sourceTree = "<group>";
};
05A8C51920DB72C200FF7857 /* Sources */ = {
isa = PBXGroup;
children = (
@ -450,6 +543,7 @@
05A8C59520DB72F000FF7857 /* frontend */,
05A8C5D420DB72F000FF7857 /* gfx */,
05A8C57120DB72F000FF7857 /* intl */,
05C5D53220E3DD0900654EE4 /* input */,
05A8C51A20DB72F000FF7857 /* menu */,
05A8C5AD20DB72F000FF7857 /* ui */,
);
@ -861,13 +955,8 @@
05A8C75720DB72F100FF7857 /* Filter.h */,
05A8C75020DB72F100FF7857 /* Filter.m */,
05A8C74820DB72F100FF7857 /* metal_common.h */,
05A8C74620DB72F100FF7857 /* MetalRenderer.h */,
05A8C74720DB72F100FF7857 /* PixelConverter.h */,
05A8C75220DB72F100FF7857 /* PixelConverter.m */,
05A8C75920DB72F100FF7857 /* PixelConverter.metal */,
05A8C74D20DB72F100FF7857 /* PixelConverter+private.h */,
05A8C74A20DB72F100FF7857 /* Renderer.h */,
05A8C75520DB72F100FF7857 /* Renderer.m */,
A902040DE66D42F9EE47BFE3 /* MenuDisplay.h */,
A902070F2C43F222FD56A95A /* MenuDisplay.m */,
05A8C74C20DB72F100FF7857 /* RendererCommon.h */,
05A8C75420DB72F100FF7857 /* RendererCommon.m */,
05A8C74E20DB72F100FF7857 /* Shaders.metal */,
@ -947,6 +1036,131 @@
path = metal_shaders;
sourceTree = "<group>";
};
05C5D53220E3DD0900654EE4 /* input */ = {
isa = PBXGroup;
children = (
05C5D57520E3DD0900654EE4 /* common */,
05C5D53520E3DD0900654EE4 /* drivers */,
05C5D56E20E3DD0900654EE4 /* drivers_hid */,
05C5D58420E3DD0900654EE4 /* drivers_joypad */,
05C5D56220E3DD0900654EE4 /* drivers_keyboard */,
05C5D54D20E3DD0900654EE4 /* include */,
05C5D58220E3DD0900654EE4 /* input_autodetect_builtin.c */,
05C5D56D20E3DD0900654EE4 /* input_defines.h */,
05C5D5A320E3DD0A00654EE4 /* input_driver.c */,
05C5D56120E3DD0900654EE4 /* input_driver.h */,
05C5D58320E3DD0900654EE4 /* input_keymaps.c */,
05C5D54C20E3DD0900654EE4 /* input_keymaps.h */,
05C5D5A120E3DD0A00654EE4 /* input_mapper.c */,
05C5D56B20E3DD0900654EE4 /* input_mapper.h */,
05C5D5A020E3DD0A00654EE4 /* input_overlay.c */,
05C5D56C20E3DD0900654EE4 /* input_overlay.h */,
05C5D5A220E3DD0A00654EE4 /* input_remapping.c */,
05C5D56A20E3DD0900654EE4 /* input_remapping.h */,
05C5D53420E3DD0900654EE4 /* input_remote.c */,
05C5D59F20E3DD0A00654EE4 /* input_remote.h */,
05C5D53320E3DD0900654EE4 /* input_types.h */,
);
name = input;
path = ../../input;
sourceTree = "<group>";
};
05C5D53520E3DD0900654EE4 /* drivers */ = {
isa = PBXGroup;
children = (
05C5D54220E3DD0900654EE4 /* cocoa_input.c */,
05C5D53820E3DD0900654EE4 /* cocoa_input.h */,
05C5D53720E3DD0900654EE4 /* nullinput.c */,
05C5D54120E3DD0900654EE4 /* sdl_input.c */,
);
path = drivers;
sourceTree = "<group>";
};
05C5D54D20E3DD0900654EE4 /* include */ = {
isa = PBXGroup;
children = (
05C5D55320E3DD0900654EE4 /* GameController */,
05C5D54E20E3DD0900654EE4 /* blissbox.h */,
05C5D56020E3DD0900654EE4 /* gamepad.h */,
05C5D55F20E3DD0900654EE4 /* hid_driver.h */,
05C5D55E20E3DD0900654EE4 /* hid_types.h */,
);
path = include;
sourceTree = "<group>";
};
05C5D55320E3DD0900654EE4 /* GameController */ = {
isa = PBXGroup;
children = (
05C5D55B20E3DD0900654EE4 /* GameController.h */,
05C5D55C20E3DD0900654EE4 /* GCController.h */,
05C5D55920E3DD0900654EE4 /* GCControllerAxisInput.h */,
05C5D55520E3DD0900654EE4 /* GCControllerButtonInput.h */,
05C5D55A20E3DD0900654EE4 /* GCControllerDirectionPad.h */,
05C5D55D20E3DD0900654EE4 /* GCControllerElement.h */,
05C5D55720E3DD0900654EE4 /* GCExtendedGamepad.h */,
05C5D55420E3DD0900654EE4 /* GCExtendedGamepadSnapshot.h */,
05C5D55620E3DD0900654EE4 /* GCGamepad.h */,
05C5D55820E3DD0900654EE4 /* GCGamepadSnapshot.h */,
);
path = GameController;
sourceTree = "<group>";
};
05C5D56220E3DD0900654EE4 /* drivers_keyboard */ = {
isa = PBXGroup;
children = (
05C5D56320E3DD0900654EE4 /* keyboard_event_apple.c */,
05C5D56620E3DD0900654EE4 /* keyboard_event_apple.h */,
);
path = drivers_keyboard;
sourceTree = "<group>";
};
05C5D56E20E3DD0900654EE4 /* drivers_hid */ = {
isa = PBXGroup;
children = (
05C5D56F20E3DD0900654EE4 /* btstack_hid.c */,
05C5D57020E3DD0900654EE4 /* null_hid.c */,
05C5D57320E3DD0900654EE4 /* iohidmanager_hid.c */,
);
path = drivers_hid;
sourceTree = "<group>";
};
05C5D57520E3DD0900654EE4 /* common */ = {
isa = PBXGroup;
children = (
05C5D57920E3DD0900654EE4 /* hid */,
05C5D57620E3DD0900654EE4 /* input_common.c */,
05C5D57720E3DD0900654EE4 /* input_x11_common.c */,
05C5D58120E3DD0900654EE4 /* input_x11_common.h */,
05C5D57820E3DD0900654EE4 /* linux_common.c */,
05C5D58020E3DD0900654EE4 /* linux_common.h */,
);
path = common;
sourceTree = "<group>";
};
05C5D57920E3DD0900654EE4 /* hid */ = {
isa = PBXGroup;
children = (
05C5D57B20E3DD0900654EE4 /* device_ds3.c */,
05C5D57C20E3DD0900654EE4 /* device_ds4.c */,
05C5D57F20E3DD0900654EE4 /* device_null.c */,
05C5D57E20E3DD0900654EE4 /* device_wiiu_gca.c */,
05C5D57D20E3DD0900654EE4 /* hid_device_driver.c */,
05C5D57A20E3DD0900654EE4 /* hid_device_driver.h */,
);
path = hid;
sourceTree = "<group>";
};
05C5D58420E3DD0900654EE4 /* drivers_joypad */ = {
isa = PBXGroup;
children = (
05C5D59820E3DD0A00654EE4 /* hid_joypad.c */,
05C5D58D20E3DD0900654EE4 /* mfi_joypad.m */,
05C5D58820E3DD0900654EE4 /* null_joypad.c */,
05C5D58720E3DD0900654EE4 /* sdl_joypad.c */,
);
path = drivers_joypad;
sourceTree = "<group>";
};
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
isa = PBXGroup;
children = (
@ -1104,7 +1318,6 @@
buildActionMask = 2147483647;
files = (
05D7753720A567A700646447 /* griffin_glslang.cpp in Sources */,
05A8C7B520DB75A800FF7857 /* PixelConverter.metal in Sources */,
05D7753520A567A400646447 /* griffin_cpp.cpp in Sources */,
509F0C9D1AA23AFC00619ECC /* griffin_objc.m in Sources */,
840222FC1A889EE2009AB261 /* griffin.c in Sources */,
@ -1146,6 +1359,7 @@
GCC_OPTIMIZATION_LEVEL = 0;
INFOPLIST_FILE = "$(SRCROOT)/OSX/Info.plist";
INSTALL_PATH = "$(HOME)/Applications";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = YES;
PRODUCT_BUNDLE_IDENTIFIER = "libretro.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = RetroArch;