mirror of
https://github.com/libretro/RetroArch
synced 2025-02-03 08:54:13 +00:00
feat(Metal): initial xmb and glui menu support
TODOs * menu shader pipeline effects * refactor / optimize graphics rendering
This commit is contained in:
parent
4135300b04
commit
5e1f991e32
@ -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
|
||||
|
@ -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
|
||||
|
27
gfx/common/metal/MenuDisplay.h
Normal file
27
gfx/common/metal/MenuDisplay.h
Normal 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
|
257
gfx/common/metal/MenuDisplay.m
Normal file
257
gfx/common/metal/MenuDisplay.m
Normal 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
|
@ -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"
|
@ -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
|
@ -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
|
@ -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
|
@ -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));
|
||||
}
|
@ -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
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -6,6 +6,7 @@
|
||||
// Copyright © 2018 Stuart Carnie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "View.h"
|
||||
#import "RendererCommon.h"
|
||||
|
||||
@implementation ViewDescriptor
|
||||
|
@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
#import "RendererCommon.h"
|
||||
#import "Renderer.h"
|
||||
#import "Context.h"
|
||||
#import "View.h"
|
||||
#import "TexturedView.h"
|
||||
#import "MenuDisplay.h"
|
||||
|
@ -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
@ -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,
|
||||
};
|
||||
|
@ -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];
|
||||
|
@ -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"
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user