mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-24 00:20:01 +00:00
feat(Metal): full xmb pipeline support
Menu TODOs: * understand why ribbon does not look the same as GL * add clear support to `MenuDisplay` for glui
This commit is contained in:
parent
4a101734a1
commit
a0900ec433
@ -11,27 +11,35 @@
|
||||
#import "RendererCommon.h"
|
||||
|
||||
@interface Texture : NSObject
|
||||
@property (readonly) id<MTLTexture> texture;
|
||||
@property (readonly) id<MTLSamplerState> sampler;
|
||||
@property (nonatomic, readonly) id<MTLTexture> texture;
|
||||
@property (nonatomic, readonly) id<MTLSamplerState> sampler;
|
||||
@end
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *data;
|
||||
NSUInteger offset;
|
||||
__unsafe_unretained id<MTLBuffer> buffer;
|
||||
} BufferRange;
|
||||
|
||||
/*! @brief Context contains the render state used by various components */
|
||||
@interface Context : NSObject
|
||||
|
||||
@property (readonly) id<MTLDevice> device;
|
||||
@property (readonly) id<MTLLibrary> library;
|
||||
@property (nonatomic, readonly) id<MTLDevice> device;
|
||||
@property (nonatomic, readonly) id<MTLLibrary> library;
|
||||
@property (nonatomic, readwrite) MTLClearColor clearColor;
|
||||
|
||||
/*! @brief Returns the command buffer used for pre-render work,
|
||||
* such as mip maps for applying filters
|
||||
* */
|
||||
@property (readonly) id<MTLCommandBuffer> blitCommandBuffer;
|
||||
@property (nonatomic, readonly) id<MTLCommandBuffer> blitCommandBuffer;
|
||||
|
||||
/*! @brief Returns the command buffer for the current frame */
|
||||
@property (readonly) id<MTLCommandBuffer> commandBuffer;
|
||||
@property (readonly) id<CAMetalDrawable> nextDrawable;
|
||||
@property (nonatomic, readonly) id<MTLCommandBuffer> commandBuffer;
|
||||
@property (nonatomic, readonly) id<CAMetalDrawable> nextDrawable;
|
||||
|
||||
/*! @brief Main render encoder to back buffer */
|
||||
@property (readonly) id<MTLRenderCommandEncoder> rce;
|
||||
@property (nonatomic, readonly) id<MTLRenderCommandEncoder> rce;
|
||||
|
||||
- (instancetype)initWithDevice:(id<MTLDevice>)d
|
||||
layer:(CAMetalLayer *)layer
|
||||
@ -40,6 +48,8 @@
|
||||
- (Texture *)newTexture:(struct texture_image)image filter:(enum texture_filter_type)filter;
|
||||
- (void)convertFormat:(RPixelFormat)fmt from:(id<MTLBuffer>)src to:(id<MTLTexture>)dst;
|
||||
|
||||
- (bool)allocRange:(BufferRange *)range length:(NSUInteger)length;
|
||||
|
||||
/*! @brief begin marks the beginning of a frame */
|
||||
- (void)begin;
|
||||
|
||||
|
@ -10,9 +10,22 @@
|
||||
#import "Filter.h"
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
@interface BufferNode : NSObject
|
||||
@property (nonatomic, readonly) id<MTLBuffer> src;
|
||||
@property (nonatomic, readwrite) NSUInteger allocated;
|
||||
@property (nonatomic, readwrite) BufferNode *next;
|
||||
@end
|
||||
|
||||
@interface BufferChain : NSObject
|
||||
- (instancetype)initWithDevice:(id<MTLDevice>)device blockLen:(NSUInteger)blockLen;
|
||||
- (bool)allocRange:(BufferRange *)range length:(NSUInteger)length;
|
||||
- (void)commitRanges;
|
||||
- (void)discard;
|
||||
@end
|
||||
|
||||
@interface Texture()
|
||||
@property (readwrite) id<MTLTexture> texture;
|
||||
@property (readwrite) id<MTLSamplerState> sampler;
|
||||
@property (nonatomic, readwrite) id<MTLTexture> texture;
|
||||
@property (nonatomic, readwrite) id<MTLSamplerState> sampler;
|
||||
@end
|
||||
|
||||
@interface Context()
|
||||
@ -32,6 +45,10 @@
|
||||
id<MTLRenderCommandEncoder> _rce;
|
||||
|
||||
id<MTLCommandBuffer> _blitCommandBuffer;
|
||||
|
||||
NSUInteger _currentChain;
|
||||
BufferChain *_chain[CHAIN_LENGTH];
|
||||
MTLClearColor _clearColor;
|
||||
}
|
||||
|
||||
- (instancetype)initWithDevice:(id<MTLDevice>)d
|
||||
@ -45,31 +62,39 @@
|
||||
_layer = layer;
|
||||
_library = l;
|
||||
_commandQueue = [_device newCommandQueue];
|
||||
_clearColor = MTLClearColorMake(0, 0, 0, 1);
|
||||
|
||||
{
|
||||
MTLSamplerDescriptor *sd = [MTLSamplerDescriptor new];
|
||||
|
||||
MTLSamplerDescriptor *sd = [MTLSamplerDescriptor new];
|
||||
sd.label = @"NEAREST";
|
||||
_samplers[TEXTURE_FILTER_NEAREST] = [d newSamplerStateWithDescriptor:sd];
|
||||
|
||||
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 = 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];
|
||||
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;
|
||||
|
||||
if (![self _initMainState])
|
||||
return nil;
|
||||
|
||||
for (int i = 0; i < CHAIN_LENGTH; i++)
|
||||
{
|
||||
_chain[i] = [[BufferChain alloc] initWithDevice:_device blockLen:65536];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -186,6 +211,12 @@
|
||||
return _blitCommandBuffer;
|
||||
}
|
||||
|
||||
- (void)_nextChain
|
||||
{
|
||||
_currentChain = (_currentChain + 1) % CHAIN_LENGTH;
|
||||
[_chain[_currentChain] discard];
|
||||
}
|
||||
|
||||
- (void)begin
|
||||
{
|
||||
assert(_commandBuffer == nil);
|
||||
@ -199,6 +230,8 @@
|
||||
if (_rce == nil)
|
||||
{
|
||||
MTLRenderPassDescriptor *rpd = [MTLRenderPassDescriptor new];
|
||||
rpd.colorAttachments[0].clearColor = _clearColor;
|
||||
rpd.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||
rpd.colorAttachments[0].texture = self.nextDrawable.texture;
|
||||
_rce = [_commandBuffer renderCommandEncoderWithDescriptor:rpd];
|
||||
}
|
||||
@ -207,7 +240,9 @@
|
||||
|
||||
- (void)end
|
||||
{
|
||||
assert(self->_commandBuffer != nil);
|
||||
assert(_commandBuffer != nil);
|
||||
|
||||
[_chain[_currentChain] commitRanges];
|
||||
|
||||
if (_blitCommandBuffer)
|
||||
{
|
||||
@ -233,9 +268,144 @@
|
||||
|
||||
_commandBuffer = nil;
|
||||
_drawable = nil;
|
||||
[self _nextChain];
|
||||
}
|
||||
|
||||
- (bool)allocRange:(BufferRange *)range length:(NSUInteger)length
|
||||
{
|
||||
return [_chain[_currentChain] allocRange:range length:length];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation Texture
|
||||
@end
|
||||
|
||||
@implementation BufferNode
|
||||
|
||||
- (instancetype)initWithBuffer:(id<MTLBuffer>)src
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_src = src;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation BufferChain
|
||||
{
|
||||
id<MTLDevice> _device;
|
||||
NSUInteger _blockLen;
|
||||
BufferNode *_head;
|
||||
NSUInteger _offset; // offset into _current
|
||||
BufferNode *_current;
|
||||
NSUInteger _length;
|
||||
NSUInteger _allocated;
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
||||
|
||||
- (instancetype)initWithDevice:(id<MTLDevice>)device blockLen:(NSUInteger)blockLen
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_device = device;
|
||||
_blockLen = blockLen;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
return [NSString stringWithFormat:@"length=%ld, allocated=%ld", _length, _allocated];
|
||||
}
|
||||
|
||||
- (void)commitRanges
|
||||
{
|
||||
for (BufferNode *n = _head; n != nil; n = n.next)
|
||||
{
|
||||
if (n.allocated > 0)
|
||||
{
|
||||
[n.src didModifyRange:NSMakeRange(0, n.allocated)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)discard
|
||||
{
|
||||
_current = _head;
|
||||
_offset = 0;
|
||||
_allocated = 0;
|
||||
}
|
||||
|
||||
- (bool)allocRange:(BufferRange *)range length:(NSUInteger)length
|
||||
{
|
||||
bzero(range, sizeof(*range));
|
||||
|
||||
if (!_head)
|
||||
{
|
||||
_head = [[BufferNode alloc] initWithBuffer:[_device newBufferWithLength:_blockLen options:MTLResourceStorageModeManaged]];
|
||||
_length += _blockLen;
|
||||
_current = _head;
|
||||
_offset = 0;
|
||||
}
|
||||
|
||||
if ([self _subAllocRange:range length:length])
|
||||
return YES;
|
||||
|
||||
while (_current.next)
|
||||
{
|
||||
[self _nextNode];
|
||||
if ([self _subAllocRange:range length:length])
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSUInteger blockLen = _blockLen;
|
||||
if (length > blockLen)
|
||||
{
|
||||
blockLen = length;
|
||||
}
|
||||
|
||||
_current.next = [[BufferNode alloc] initWithBuffer:[_device newBufferWithLength:blockLen options:MTLResourceStorageModeManaged]];
|
||||
if (!_current.next)
|
||||
return NO;
|
||||
|
||||
_length += blockLen;
|
||||
|
||||
[self _nextNode];
|
||||
retro_assert([self _subAllocRange:range length:length]);
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)_nextNode
|
||||
{
|
||||
_current = _current.next;
|
||||
_offset = 0;
|
||||
}
|
||||
|
||||
- (BOOL)_subAllocRange:(BufferRange *)range length:(NSUInteger)length
|
||||
{
|
||||
NSUInteger nextOffset = _offset + length;
|
||||
if (nextOffset <= _current.src.length)
|
||||
{
|
||||
_current.allocated = nextOffset;
|
||||
_allocated += length;
|
||||
range->data = _current.src.contents + _offset;
|
||||
range->buffer = _current.src;
|
||||
range->offset = _offset;
|
||||
_offset = MTL_ALIGN_BUFFER(nextOffset);
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
@ -15,8 +15,8 @@
|
||||
|
||||
@interface Filter : NSObject
|
||||
|
||||
@property (readwrite) id<FilterDelegate> delegate;
|
||||
@property (readonly) id<MTLSamplerState> sampler;
|
||||
@property (nonatomic, readwrite) id<FilterDelegate> delegate;
|
||||
@property (nonatomic, readonly) id<MTLSamplerState> sampler;
|
||||
|
||||
-(void)apply:(id<MTLCommandBuffer>)cb in:(id<MTLTexture>)tin out:(id<MTLTexture>)tout;
|
||||
-(void)apply:(id<MTLCommandBuffer>)cb inBuf:(id<MTLBuffer>)tin outTex:(id<MTLTexture>)tout;
|
||||
|
@ -10,8 +10,8 @@
|
||||
|
||||
@interface MenuDisplay : NSObject
|
||||
|
||||
@property (readwrite) BOOL blend;
|
||||
@property (readwrite) MTLClearColor clearColor;
|
||||
@property (nonatomic, readwrite) BOOL blend;
|
||||
@property (nonatomic, readwrite) MTLClearColor clearColor;
|
||||
|
||||
- (instancetype)initWithDriver:(MetalDriver *)driver;
|
||||
- (void)drawPipeline:(menu_display_ctx_draw_t *)draw video:(video_frame_info_t *)video;
|
||||
@ -22,7 +22,6 @@
|
||||
+ (const float *)defaultVertices;
|
||||
+ (const float *)defaultTexCoords;
|
||||
+ (const float *)defaultColor;
|
||||
+ (const float *)defaultMatrix;
|
||||
|
||||
|
||||
@end
|
||||
|
@ -45,10 +45,10 @@
|
||||
+ (const float *)defaultTexCoords
|
||||
{
|
||||
static float dummy[] = {
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
};
|
||||
return &dummy[0];
|
||||
}
|
||||
@ -64,17 +64,6 @@
|
||||
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;
|
||||
@ -100,133 +89,103 @@
|
||||
}
|
||||
}
|
||||
|
||||
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)drawPipeline:(menu_display_ctx_draw_t *)draw video:(video_frame_info_t *)video
|
||||
{
|
||||
|
||||
static struct video_coords blank_coords;
|
||||
|
||||
draw->x = 0;
|
||||
draw->y = 0;
|
||||
draw->matrix_data = NULL;
|
||||
|
||||
_uniforms.outputSize = simd_make_float2(_driver.viewport->full_width, _driver.viewport->full_height);
|
||||
|
||||
draw->pipeline.backend_data = &_uniforms;
|
||||
draw->pipeline.backend_data_size = sizeof(_uniforms);
|
||||
|
||||
switch (draw->pipeline.id)
|
||||
{
|
||||
// ribbon
|
||||
default:
|
||||
case VIDEO_SHADER_MENU:
|
||||
case VIDEO_SHADER_MENU_2:
|
||||
{
|
||||
video_coord_array_t *ca = menu_display_get_coords_array();
|
||||
draw->coords = (struct video_coords *)&ca->coords;
|
||||
break;
|
||||
}
|
||||
|
||||
case VIDEO_SHADER_MENU_3:
|
||||
case VIDEO_SHADER_MENU_4:
|
||||
case VIDEO_SHADER_MENU_5:
|
||||
case VIDEO_SHADER_MENU_6:
|
||||
{
|
||||
draw->coords = &blank_coords;
|
||||
blank_coords.vertices = 4;
|
||||
draw->prim_type = MENU_DISPLAY_PRIM_TRIANGLESTRIP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_uniforms.time += 0.01;
|
||||
}
|
||||
|
||||
- (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;
|
||||
const float *vertex = draw->coords->vertex ?: MenuDisplay.defaultVertices;
|
||||
const float *tex_coord = draw->coords->tex_coord ?: MenuDisplay.defaultTexCoords;
|
||||
const float *color = draw->coords->color ?: MenuDisplay.defaultColor;
|
||||
|
||||
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)
|
||||
NSUInteger needed = draw->coords->vertices * sizeof(SpriteVertex);
|
||||
BufferRange range;
|
||||
if (![_context allocRange:&range length:needed])
|
||||
{
|
||||
write_quad4a(pv,
|
||||
draw->x,
|
||||
draw->y,
|
||||
draw->width,
|
||||
draw->height,
|
||||
draw->scale_factor,
|
||||
0.0, 0.0, 1.0, 1.0, color);
|
||||
RARCH_ERR("[Metal]: MenuDisplay unable to allocate buffer of %d bytes", needed);
|
||||
return;
|
||||
}
|
||||
|
||||
NSUInteger vertexCount = draw->coords->vertices;
|
||||
SpriteVertex *pv = (SpriteVertex *)range.data;
|
||||
for (unsigned i = 0; i < draw->coords->vertices; i++, pv++)
|
||||
{
|
||||
pv->position = simd_make_float2(vertex[0], 1.0 - vertex[1]);
|
||||
vertex += 2;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
id<MTLRenderCommandEncoder> rce = _context.rce;
|
||||
MTLViewport vp = {
|
||||
.originX = draw->x,
|
||||
.originY = _driver.viewport->full_height - draw->y - draw->height,
|
||||
.width = draw->width,
|
||||
.height = draw->height,
|
||||
.znear = 0,
|
||||
.zfar = 1,
|
||||
};
|
||||
[rce setViewport:vp];
|
||||
|
||||
switch (draw->pipeline.id)
|
||||
{
|
||||
#ifdef HAVE_SHADERPIPELINE
|
||||
#if HAVE_SHADERPIPELINE
|
||||
case VIDEO_SHADER_MENU:
|
||||
case VIDEO_SHADER_MENU_2:
|
||||
case VIDEO_SHADER_MENU_3:
|
||||
case VIDEO_SHADER_MENU_4:
|
||||
case VIDEO_SHADER_MENU_5:
|
||||
case VIDEO_SHADER_MENU_6:
|
||||
{
|
||||
[rce setRenderPipelineState:[_driver getStockShader:draw->pipeline.id blend:_blend]];
|
||||
[rce setVertexBytes:draw->pipeline.backend_data length:draw->pipeline.backend_data_size atIndex:BufferIndexUniforms];
|
||||
[rce setVertexBuffer:range.buffer offset:range.offset atIndex:BufferIndexPositions];
|
||||
[rce setFragmentBytes:draw->pipeline.backend_data length:draw->pipeline.backend_data_size atIndex:BufferIndexUniforms];
|
||||
[rce drawPrimitives:[self _toPrimitiveType:draw->prim_type] vertexStart:0 vertexCount:vertexCount];
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
@ -235,15 +194,17 @@ static INLINE void write_quad4a(SpriteVertex *pv,
|
||||
// TODO(sgc): draw quad to clear
|
||||
_clearNextRender = NO;
|
||||
}
|
||||
|
||||
id<MTLRenderCommandEncoder> rce = _context.rce;
|
||||
|
||||
[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];
|
||||
Uniforms uniforms = {
|
||||
.projectionMatrix = draw->matrix_data ? *(matrix_float4x4 *)draw->matrix_data
|
||||
: _uniforms.projectionMatrix
|
||||
};
|
||||
[rce setVertexBytes:&uniforms length:sizeof(uniforms) atIndex:BufferIndexUniforms];
|
||||
[rce setVertexBuffer:range.buffer offset:range.offset atIndex:BufferIndexPositions];
|
||||
[rce setFragmentTexture:tex.texture atIndex:TextureIndexColor];
|
||||
[rce setFragmentSamplerState:tex.sampler atIndex:SamplerIndexDraw];
|
||||
[rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
||||
[rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:vertexCount];
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -14,6 +14,16 @@
|
||||
// TODO(sgc): implement triple buffering
|
||||
/*! @brief maximum inflight frames */
|
||||
#define MAX_INFLIGHT 1
|
||||
#define CHAIN_LENGTH 3
|
||||
|
||||
/* macOS requires constants in a buffer to have a 256 byte alignment. */
|
||||
#ifdef TARGET_OS_MAC
|
||||
#define kMetalBufferAlignment 256
|
||||
#else
|
||||
#define kMetalBufferAlignment 4
|
||||
#endif
|
||||
|
||||
#define MTL_ALIGN_BUFFER(size) ((size + kMetalBufferAlignment - 1) & (~(kMetalBufferAlignment - 1)))
|
||||
|
||||
#pragma mark - Pixel Formats
|
||||
|
||||
|
@ -62,10 +62,10 @@ matrix_float4x4 matrix_proj_ortho(float left, float right, float top, float bott
|
||||
float ty = (top + bottom) / (bottom - top);
|
||||
float tz = near / (far - near);
|
||||
|
||||
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};
|
||||
simd_float4 P = simd_make_float4(sx, 0, 0, 0);
|
||||
simd_float4 Q = simd_make_float4(0, sy, 0, 0);
|
||||
simd_float4 R = simd_make_float4(0, 0, sz, 0);
|
||||
simd_float4 S = simd_make_float4(tx, ty, tz, 1);
|
||||
|
||||
matrix_float4x4 mat = {P, Q, R, S};
|
||||
return mat;
|
||||
|
@ -6,12 +6,12 @@
|
||||
|
||||
@interface TexturedView : 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;
|
||||
@property (nonatomic, readonly) RPixelFormat format;
|
||||
@property (nonatomic, readonly) RTextureFilter filter;
|
||||
@property (nonatomic, readwrite) BOOL visible;
|
||||
@property (nonatomic, readwrite) CGRect frame;
|
||||
@property (nonatomic, readwrite) CGSize size;
|
||||
@property (nonatomic, readonly) ViewDrawState drawState;
|
||||
|
||||
- (instancetype)initWithDescriptor:(ViewDescriptor *)td context:(Context *)c;
|
||||
|
||||
|
@ -20,9 +20,9 @@ typedef NS_ENUM(NSInteger, ViewDrawState)
|
||||
};
|
||||
|
||||
@interface ViewDescriptor : NSObject
|
||||
@property (readwrite) RPixelFormat format;
|
||||
@property (readwrite) RTextureFilter filter;
|
||||
@property (readwrite) CGSize size;
|
||||
@property (nonatomic, readwrite) RPixelFormat format;
|
||||
@property (nonatomic, readwrite) RTextureFilter filter;
|
||||
@property (nonatomic, readwrite) CGSize size;
|
||||
|
||||
- (instancetype)init;
|
||||
@end
|
||||
|
273
gfx/common/metal/menu_pipeline.metal
Normal file
273
gfx/common/metal/menu_pipeline.metal
Normal file
@ -0,0 +1,273 @@
|
||||
//
|
||||
// pipeline_ribbon.metal
|
||||
// RetroArch
|
||||
//
|
||||
// Created by Stuart Carnie on 6/30/18.
|
||||
//
|
||||
|
||||
#include <metal_stdlib>
|
||||
|
||||
#import "ShaderTypes.h"
|
||||
|
||||
using namespace metal;
|
||||
|
||||
#pragma mark - ribbon simple
|
||||
|
||||
namespace ribbon {
|
||||
|
||||
float iqhash(float n)
|
||||
{
|
||||
return fract(sin(n) * 43758.5453);
|
||||
}
|
||||
|
||||
float noise(float3 x)
|
||||
{
|
||||
float3 p = floor(x);
|
||||
float3 f = fract(x);
|
||||
f = f * f * (3.0 - 2.0 * f);
|
||||
float n = p.x + p.y * 57.0 + 113.0 * p.z;
|
||||
return mix(mix(mix(iqhash(n), iqhash(n + 1.0), f.x),
|
||||
mix(iqhash(n + 57.0), iqhash(n + 58.0), f.x), f.y),
|
||||
mix(mix(iqhash(n + 113.0), iqhash(n + 114.0), f.x),
|
||||
mix(iqhash(n + 170.0), iqhash(n + 171.0), f.x), f.y), f.z);
|
||||
}
|
||||
|
||||
float xmb_noise2(float3 x, const device Uniforms &constants)
|
||||
{
|
||||
return cos(x.z * 4.0) * cos(x.z + constants.time / 10.0 + x.x);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#pragma mark - ribbon simple
|
||||
|
||||
vertex FontFragmentIn ribbon_simple_vertex(const SpriteVertex in [[ stage_in ]], const device Uniforms &constants [[ buffer(BufferIndexUniforms) ]])
|
||||
{
|
||||
float4 t = (constants.projectionMatrix * float4(in.position, 0, 1));
|
||||
|
||||
float3 v = float3(t.x, 0.0, 1.0-t.y);
|
||||
float3 v2 = v;
|
||||
|
||||
v2.x = v2.x + constants.time / 2.0;
|
||||
v2.z = v.z * 3.0;
|
||||
v.y = cos((v.x + v.z / 3.0 + constants.time) * 2.0) / 10.0 + ribbon::noise(v2.xyz) / 4.0;
|
||||
v.y = -v.y;
|
||||
|
||||
FontFragmentIn out;
|
||||
out.position = float4(v, 1.0);
|
||||
return out;
|
||||
}
|
||||
|
||||
fragment float4 ribbon_simple_fragment()
|
||||
{
|
||||
return float4(0.05, 0.05, 0.05, 1.0);
|
||||
}
|
||||
|
||||
#pragma mark - ribbon
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vector_float4 position [[position]];
|
||||
vector_float3 vEC;
|
||||
} RibbonOutIn;
|
||||
|
||||
|
||||
vertex RibbonOutIn ribbon_vertex(const SpriteVertex in [[ stage_in ]], const device Uniforms &constants [[ buffer(BufferIndexUniforms) ]])
|
||||
{
|
||||
float4 t = (constants.projectionMatrix * float4(in.position, 0, 1));
|
||||
|
||||
float3 v = float3(t.x, 0.0, 1.0-t.y);
|
||||
float3 v2 = v;
|
||||
float3 v3 = v;
|
||||
|
||||
v.y = ribbon::xmb_noise2(v2, constants) / 8.0;
|
||||
|
||||
v3.x -= constants.time / 5.0;
|
||||
v3.x /= 4.0;
|
||||
|
||||
v3.z -= constants.time / 10.0;
|
||||
v3.y -= constants.time / 100.0;
|
||||
|
||||
v.z -= ribbon::noise(v3 * 7.0) / 15.0;
|
||||
v.y -= ribbon::noise(v3 * 7.0) / 15.0 + cos(v.x * 2.0 - constants.time / 2.0) / 5.0 - 0.3;
|
||||
v.y = -v.y;
|
||||
|
||||
RibbonOutIn out;
|
||||
out.vEC = v;
|
||||
out.position = float4(v, 1.0);
|
||||
return out;
|
||||
}
|
||||
|
||||
fragment float4 ribbon_fragment(RibbonOutIn in [[ stage_in ]])
|
||||
{
|
||||
const float3 up = float3(0.0, 0.0, 1.0);
|
||||
float3 x = dfdx(in.vEC);
|
||||
float3 y = dfdy(in.vEC);
|
||||
float3 normal = normalize(cross(x, y));
|
||||
float c = 1.0 - dot(normal, up);
|
||||
c = (1.0 - cos(c * c)) / 13.0;
|
||||
return float4(c, c, c, 1.0);
|
||||
}
|
||||
|
||||
#pragma mark - snow constants
|
||||
|
||||
constant float snowBaseScale [[ function_constant(0) ]]; // [1.0 .. 10.0]
|
||||
constant float snowDensity [[ function_constant(1) ]]; // [0.01 .. 1.0]
|
||||
constant float snowSpeed [[ function_constant(2) ]]; // [0.1 .. 1.0]
|
||||
|
||||
#pragma mark - snow simple
|
||||
|
||||
namespace snow
|
||||
{
|
||||
|
||||
float rand(float2 co)
|
||||
{
|
||||
return fract(sin(dot(co.xy, float2(12.9898, 78.233))) * 43758.5453);
|
||||
}
|
||||
|
||||
float dist_func(float2 distv)
|
||||
{
|
||||
float dist = sqrt((distv.x * distv.x) + (distv.y * distv.y)) * (40.0 / snowBaseScale);
|
||||
dist = clamp(dist, 0.0, 1.0);
|
||||
return cos(dist * (3.14159265358 * 0.5)) * 0.5;
|
||||
}
|
||||
|
||||
float random_dots(float2 co)
|
||||
{
|
||||
float part = 1.0 / 20.0;
|
||||
float2 cd = floor(co / part);
|
||||
float p = rand(cd);
|
||||
|
||||
if (p > 0.005 * (snowDensity * 40.0))
|
||||
return 0.0;
|
||||
|
||||
float2 dpos = (float2(fract(p * 2.0) , p) + float2(2.0, 2.0)) * 0.25;
|
||||
|
||||
float2 cellpos = fract(co / part);
|
||||
float2 distv = (cellpos - dpos);
|
||||
|
||||
return dist_func(distv);
|
||||
}
|
||||
|
||||
float snow(float2 pos, float time, float scale)
|
||||
{
|
||||
// add wobble
|
||||
pos.x += cos(pos.y * 1.2 + time * 3.14159 * 2.0 + 1.0 / scale) / (8.0 / scale) * 4.0;
|
||||
// add gravity
|
||||
pos += time * scale * float2(-0.5, 1.0) * 4.0;
|
||||
return random_dots(pos / scale) * (scale * 0.5 + 0.5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fragment float4 snow_fragment(FontFragmentIn in [[ stage_in ]],
|
||||
const device Uniforms &constants [[ buffer(BufferIndexUniforms) ]])
|
||||
{
|
||||
float tim = constants.time * 0.4 * snowSpeed;
|
||||
float2 pos = in.position.xy / constants.outputSize.xx;
|
||||
pos.y = 1.0 - pos.y; // Flip Y
|
||||
float a = 0.0;
|
||||
// Each of these is a layer of snow
|
||||
// Remove some for better performance
|
||||
// Changing the scale (3rd value) will mess with the looping
|
||||
a += snow::snow(pos, tim, 1.0);
|
||||
a += snow::snow(pos, tim, 0.7);
|
||||
a += snow::snow(pos, tim, 0.6);
|
||||
a += snow::snow(pos, tim, 0.5);
|
||||
a += snow::snow(pos, tim, 0.4);
|
||||
a += snow::snow(pos, tim, 0.3);
|
||||
a += snow::snow(pos, tim, 0.25);
|
||||
a += snow::snow(pos, tim, 0.125);
|
||||
a = a * min(pos.y * 4.0, 1.0);
|
||||
return float4(1.0, 1.0, 1.0, a);
|
||||
}
|
||||
|
||||
fragment float4 bokeh_fragment(FontFragmentIn in [[ stage_in ]],
|
||||
const device Uniforms &constants [[ buffer(BufferIndexUniforms) ]])
|
||||
{
|
||||
float speed = constants.time * 4.0;
|
||||
float2 uv = -1.0 + 2.0 * in.position.xy / constants.outputSize;
|
||||
uv.x *= constants.outputSize.x / constants.outputSize.y;
|
||||
float3 color = float3(0.0);
|
||||
|
||||
for( int i=0; i < 8; i++ )
|
||||
{
|
||||
float pha = sin(float(i) * 546.13 + 1.0) * 0.5 + 0.5;
|
||||
float siz = pow(sin(float(i) * 651.74 + 5.0) * 0.5 + 0.5, 4.0);
|
||||
float pox = sin(float(i) * 321.55 + 4.1) * constants.outputSize.x / constants.outputSize.y;
|
||||
float rad = 0.1 + 0.5 * siz + sin(pha + siz) / 4.0;
|
||||
float2 pos = float2(pox + sin(speed / 15. + pha + siz), - 1.0 - rad + (2.0 + 2.0 * rad) * fract(pha + 0.3 * (speed / 7.) * (0.2 + 0.8 * siz)));
|
||||
float dis = length(uv - pos);
|
||||
if(dis < rad)
|
||||
{
|
||||
float3 col = mix(float3(0.194 * sin(speed / 6.0) + 0.3, 0.2, 0.3 * pha), float3(1.1 * sin(speed / 9.0) + 0.3, 0.2 * pha, 0.4), 0.5 + 0.5 * sin(float(i)));
|
||||
color += col.zyx * (1.0 - smoothstep(rad * 0.15, rad, dis));
|
||||
}
|
||||
}
|
||||
color *= sqrt(1.5 - 0.5 * length(uv));
|
||||
return float4(color.r, color.g, color.b , 0.5);
|
||||
}
|
||||
|
||||
namespace snowflake {
|
||||
|
||||
float rand_float(float x)
|
||||
{
|
||||
return snow::rand(float2(x, 1.0));
|
||||
}
|
||||
|
||||
float snow(float3 pos, float2 uv, float o, float atime)
|
||||
{
|
||||
float2 d = (pos.xy - uv);
|
||||
float a = atan(d.y / d.x) + sin(atime*1.0 + o) * 10.0;
|
||||
|
||||
float dist = d.x*d.x + d.y*d.y;
|
||||
|
||||
if(dist < pos.z/400.0)
|
||||
{
|
||||
float col = 0.0;
|
||||
if(sin(a * 8.0) < 0.0)
|
||||
{
|
||||
col=1.0;
|
||||
}
|
||||
if(dist < pos.z/800.0)
|
||||
{
|
||||
col+=1.0;
|
||||
}
|
||||
return col * pos.z;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
float col(float2 c, const device Uniforms &constants)
|
||||
{
|
||||
float color = 0.0;
|
||||
float atime = (constants.time + 1.0) / 4.0;
|
||||
|
||||
for (int i = 1; i < 15; i++)
|
||||
{
|
||||
float o = rand_float(float(i) / 3.0) * 15.0;
|
||||
float z = rand_float(float(i) + 13.0);
|
||||
float x = 1.8 - (3.6) * (rand_float(floor((constants.time*((z + 1.0) / 2.0) +o) / 2.0)) + sin(constants.time * o /1000.0) / 10.0);
|
||||
float y = 1.0 - fmod((constants.time * ((z + 1.0)/2.0)) + o, 2.0);
|
||||
|
||||
color += snow(float3(x,y,z), c, o, atime);
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fragment float4 snowflake_fragment(FontFragmentIn in [[ stage_in ]],
|
||||
const device Uniforms &constants [[ buffer(BufferIndexUniforms) ]])
|
||||
{
|
||||
float2 uv = in.position.xy / constants.outputSize.xy;
|
||||
uv = uv * 2.0 - 1.0;
|
||||
float2 p = uv;
|
||||
p.x *= constants.outputSize.x / constants.outputSize.y;
|
||||
//p.y = -p.y;
|
||||
|
||||
float c = snowflake::col(p, constants);
|
||||
return float4(c,c,c,c);
|
||||
}
|
@ -28,14 +28,14 @@ extern MTLPixelFormat SelectOptimalPixelFormat(MTLPixelFormat fmt);
|
||||
|
||||
@interface FrameView : 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;
|
||||
@property (readonly) struct video_shader* shader;
|
||||
@property (readwrite) uint64_t frameCount;
|
||||
@property (nonatomic, readonly) RPixelFormat format;
|
||||
@property (nonatomic, readonly) RTextureFilter filter;
|
||||
@property (nonatomic, readwrite) BOOL visible;
|
||||
@property (nonatomic, readwrite) CGRect frame;
|
||||
@property (nonatomic, readwrite) CGSize size;
|
||||
@property (nonatomic, readonly) ViewDrawState drawState;
|
||||
@property (nonatomic, readonly) struct video_shader* shader;
|
||||
@property (nonatomic, readwrite) uint64_t frameCount;
|
||||
|
||||
- (void)setFilteringIndex:(int)index smooth:(bool)smooth;
|
||||
- (BOOL)setShaderFromPath:(NSString *)path;
|
||||
@ -46,9 +46,9 @@ extern MTLPixelFormat SelectOptimalPixelFormat(MTLPixelFormat fmt);
|
||||
|
||||
@interface MetalMenu : NSObject
|
||||
|
||||
@property (readonly) bool hasFrame;
|
||||
@property (readwrite) bool enabled;
|
||||
@property (readwrite) float alpha;
|
||||
@property (nonatomic, readonly) bool hasFrame;
|
||||
@property (nonatomic, readwrite) bool enabled;
|
||||
@property (nonatomic, readwrite) float alpha;
|
||||
|
||||
- (void)updateFrame:(void const *)source;
|
||||
|
||||
@ -60,20 +60,20 @@ extern MTLPixelFormat SelectOptimalPixelFormat(MTLPixelFormat fmt);
|
||||
|
||||
@interface MetalDriver : NSObject<MTKViewDelegate>
|
||||
|
||||
@property (readonly) video_viewport_t* viewport;
|
||||
@property (readwrite) bool keepAspect;
|
||||
@property (readonly) MetalMenu* menu;
|
||||
@property (readonly) FrameView* frameView;
|
||||
@property (readonly) MenuDisplay* display;
|
||||
@property (readonly) Context* context;
|
||||
@property (readonly) Uniforms* viewportMVP;
|
||||
@property (nonatomic, readonly) video_viewport_t* viewport;
|
||||
@property (nonatomic, readwrite) bool keepAspect;
|
||||
@property (nonatomic, readonly) MetalMenu* menu;
|
||||
@property (nonatomic, readonly) FrameView* frameView;
|
||||
@property (nonatomic, readonly) MenuDisplay* display;
|
||||
@property (nonatomic, readonly) Context* context;
|
||||
@property (nonatomic, readonly) Uniforms* viewportMVP;
|
||||
@property (nonatomic, readonly) Uniforms* viewportMVPNormalized;
|
||||
|
||||
- (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
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
@interface FrameView()
|
||||
|
||||
@property (readwrite) video_viewport_t *viewport;
|
||||
@property (nonatomic, readwrite) video_viewport_t *viewport;
|
||||
|
||||
- (instancetype)initWithDescriptor:(ViewDescriptor *)td context:(Context *)context;
|
||||
- (void)drawWithContext:(Context *)ctx;
|
||||
@ -41,7 +41,7 @@
|
||||
@end
|
||||
|
||||
@interface MetalMenu()
|
||||
@property (readonly) TexturedView *view;
|
||||
@property (nonatomic, readonly) TexturedView *view;
|
||||
- (instancetype)initWithContext:(Context *)context;
|
||||
@end
|
||||
|
||||
@ -71,7 +71,7 @@
|
||||
// other state
|
||||
Uniforms _uniforms;
|
||||
Uniforms _viewportMVP;
|
||||
BOOL _begin, _end;
|
||||
Uniforms _viewportMVPNormalized;
|
||||
}
|
||||
|
||||
- (instancetype)initWithVideo:(const video_info_t *)video
|
||||
@ -96,9 +96,6 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
_begin = NO;
|
||||
_end = NO;
|
||||
|
||||
_video = *video;
|
||||
_viewport = (video_viewport_t *)calloc(1, sizeof(video_viewport_t));
|
||||
|
||||
@ -221,15 +218,15 @@
|
||||
|
||||
{
|
||||
MTLRenderPipelineDescriptor *psd = [MTLRenderPipelineDescriptor new];
|
||||
psd.label = @"stock_no_blend";
|
||||
psd.label = @"stock";
|
||||
|
||||
MTLRenderPipelineColorAttachmentDescriptor *ca = psd.colorAttachments[0];
|
||||
ca.pixelFormat = _layer.pixelFormat;
|
||||
ca.blendingEnabled = NO;
|
||||
ca.sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha;
|
||||
ca.sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
|
||||
ca.destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||
ca.destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||
ca.sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha;
|
||||
ca.destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||
|
||||
psd.sampleCount = 1;
|
||||
psd.vertexDescriptor = vd;
|
||||
@ -243,7 +240,7 @@
|
||||
RARCH_ERR("[Metal]: error creating pipeline state %s\n", err.localizedDescription.UTF8String);
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
psd.label = @"stock_blend";
|
||||
ca.blendingEnabled = YES;
|
||||
_states[VIDEO_SHADER_STOCK_BLEND][1] = [_device newRenderPipelineStateWithDescriptor:psd error:&err];
|
||||
@ -252,6 +249,114 @@
|
||||
RARCH_ERR("[Metal]: error creating pipeline state %s\n", err.localizedDescription.UTF8String);
|
||||
return NO;
|
||||
}
|
||||
|
||||
MTLFunctionConstantValues *vals;
|
||||
|
||||
psd.label = @"snow_simple";
|
||||
ca.blendingEnabled = YES;
|
||||
{
|
||||
vals = [MTLFunctionConstantValues new];
|
||||
float values[3] = {
|
||||
1.25f, // baseScale
|
||||
0.50f, // density
|
||||
0.15f, // speed
|
||||
};
|
||||
[vals setConstantValue:&values[0] type:MTLDataTypeFloat withName:@"snowBaseScale"];
|
||||
[vals setConstantValue:&values[1] type:MTLDataTypeFloat withName:@"snowDensity"];
|
||||
[vals setConstantValue:&values[2] type:MTLDataTypeFloat withName:@"snowSpeed"];
|
||||
}
|
||||
psd.fragmentFunction = [_library newFunctionWithName:@"snow_fragment" constantValues:vals error:&err];
|
||||
_states[VIDEO_SHADER_MENU_3][1] = [_device newRenderPipelineStateWithDescriptor:psd error:&err];
|
||||
if (err != nil)
|
||||
{
|
||||
RARCH_ERR("[Metal]: error creating pipeline state %s\n", err.localizedDescription.UTF8String);
|
||||
return NO;
|
||||
}
|
||||
|
||||
psd.label = @"snow";
|
||||
ca.blendingEnabled = YES;
|
||||
{
|
||||
vals = [MTLFunctionConstantValues new];
|
||||
float values[3] = {
|
||||
3.50f, // baseScale
|
||||
0.70f, // density
|
||||
0.25f, // speed
|
||||
};
|
||||
[vals setConstantValue:&values[0] type:MTLDataTypeFloat withName:@"snowBaseScale"];
|
||||
[vals setConstantValue:&values[1] type:MTLDataTypeFloat withName:@"snowDensity"];
|
||||
[vals setConstantValue:&values[2] type:MTLDataTypeFloat withName:@"snowSpeed"];
|
||||
}
|
||||
psd.fragmentFunction = [_library newFunctionWithName:@"snow_fragment" constantValues:vals error:&err];
|
||||
_states[VIDEO_SHADER_MENU_4][1] = [_device newRenderPipelineStateWithDescriptor:psd error:&err];
|
||||
if (err != nil)
|
||||
{
|
||||
RARCH_ERR("[Metal]: error creating pipeline state %s\n", err.localizedDescription.UTF8String);
|
||||
return NO;
|
||||
}
|
||||
|
||||
psd.label = @"bokeh";
|
||||
ca.blendingEnabled = YES;
|
||||
psd.fragmentFunction = [_library newFunctionWithName:@"bokeh_fragment"];
|
||||
_states[VIDEO_SHADER_MENU_5][1] = [_device newRenderPipelineStateWithDescriptor:psd error:&err];
|
||||
if (err != nil)
|
||||
{
|
||||
RARCH_ERR("[Metal]: error creating pipeline state %s\n", err.localizedDescription.UTF8String);
|
||||
return NO;
|
||||
}
|
||||
|
||||
psd.label = @"snowflake";
|
||||
ca.blendingEnabled = YES;
|
||||
psd.fragmentFunction = [_library newFunctionWithName:@"snowflake_fragment"];
|
||||
_states[VIDEO_SHADER_MENU_6][1] = [_device newRenderPipelineStateWithDescriptor:psd error:&err];
|
||||
if (err != nil)
|
||||
{
|
||||
RARCH_ERR("[Metal]: error creating pipeline state %s\n", err.localizedDescription.UTF8String);
|
||||
return NO;
|
||||
}
|
||||
|
||||
psd.label = @"ribbon";
|
||||
ca.blendingEnabled = NO;
|
||||
psd.vertexFunction = [_library newFunctionWithName:@"ribbon_vertex"];
|
||||
psd.fragmentFunction = [_library newFunctionWithName:@"ribbon_fragment"];
|
||||
_states[VIDEO_SHADER_MENU][0] = [_device newRenderPipelineStateWithDescriptor:psd error:&err];
|
||||
if (err != nil)
|
||||
{
|
||||
RARCH_ERR("[Metal]: error creating pipeline state %s\n", err.localizedDescription.UTF8String);
|
||||
return NO;
|
||||
}
|
||||
|
||||
psd.label = @"ribbon_blend";
|
||||
ca.blendingEnabled = YES;
|
||||
ca.sourceRGBBlendFactor = MTLBlendFactorOne;
|
||||
ca.destinationRGBBlendFactor = MTLBlendFactorOne;
|
||||
_states[VIDEO_SHADER_MENU][1] = [_device newRenderPipelineStateWithDescriptor:psd error:&err];
|
||||
if (err != nil)
|
||||
{
|
||||
RARCH_ERR("[Metal]: error creating pipeline state %s\n", err.localizedDescription.UTF8String);
|
||||
return NO;
|
||||
}
|
||||
|
||||
psd.label = @"ribbon_simple";
|
||||
ca.blendingEnabled = NO;
|
||||
psd.vertexFunction = [_library newFunctionWithName:@"ribbon_simple_vertex"];
|
||||
psd.fragmentFunction = [_library newFunctionWithName:@"ribbon_simple_fragment"];
|
||||
_states[VIDEO_SHADER_MENU_2][0] = [_device newRenderPipelineStateWithDescriptor:psd error:&err];
|
||||
if (err != nil)
|
||||
{
|
||||
RARCH_ERR("[Metal]: error creating pipeline state %s\n", err.localizedDescription.UTF8String);
|
||||
return NO;
|
||||
}
|
||||
|
||||
psd.label = @"ribbon_simple_blend";
|
||||
ca.blendingEnabled = YES;
|
||||
ca.sourceRGBBlendFactor = MTLBlendFactorOne;
|
||||
ca.destinationRGBBlendFactor = MTLBlendFactorOne;
|
||||
_states[VIDEO_SHADER_MENU_2][1] = [_device newRenderPipelineStateWithDescriptor:psd error:&err];
|
||||
if (err != nil)
|
||||
{
|
||||
RARCH_ERR("[Metal]: error creating pipeline state %s\n", err.localizedDescription.UTF8String);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
@ -261,18 +366,44 @@
|
||||
_uniforms.projectionMatrix = matrix_proj_ortho(0, 1, 0, 1);
|
||||
}
|
||||
|
||||
- (void)_updateViewport:(CGSize)size
|
||||
{
|
||||
_viewport->full_width = (unsigned int)size.width;
|
||||
_viewport->full_height = (unsigned int)size.height;
|
||||
video_driver_set_size(&_viewport->full_width, &_viewport->full_height);
|
||||
_layer.drawableSize = size;
|
||||
video_driver_update_viewport(_viewport, NO, _keepAspect);
|
||||
|
||||
_viewportMVP.outputSize = simd_make_float2(_viewport->full_width, _viewport->full_height);
|
||||
_viewportMVP.projectionMatrix = matrix_proj_ortho(0, _viewport->full_width, _viewport->full_height, 0);
|
||||
_viewportMVP.projectionMatrix = matrix_proj_ortho(0, _viewport->full_width, 0, _viewport->full_height);
|
||||
|
||||
_viewportMVPNormalized.outputSize = simd_make_float2(_viewport->full_width, _viewport->full_height);
|
||||
_viewportMVPNormalized.projectionMatrix = matrix_proj_ortho(0, 1, 0, 1);
|
||||
}
|
||||
|
||||
#pragma mark - shaders
|
||||
|
||||
- (id<MTLRenderPipelineState>)getStockShader:(int)index blend:(bool)blend
|
||||
{
|
||||
assert(index > 0 && index < GFX_MAX_SHADERS);
|
||||
|
||||
return _states[index][blend ? 1 : 0];
|
||||
}
|
||||
|
||||
- (void)setShaderIndex:(NSUInteger)index
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case VIDEO_SHADER_STOCK_BLEND:
|
||||
case VIDEO_SHADER_MENU:
|
||||
case VIDEO_SHADER_MENU_2:
|
||||
case VIDEO_SHADER_MENU_3:
|
||||
case VIDEO_SHADER_MENU_4:
|
||||
case VIDEO_SHADER_MENU_5:
|
||||
case VIDEO_SHADER_MENU_6:
|
||||
break;
|
||||
default:
|
||||
index = VIDEO_SHADER_STOCK_BLEND;
|
||||
break;
|
||||
}
|
||||
|
||||
return _states[index][blend ? 1 : 0];
|
||||
}
|
||||
|
||||
#pragma mark - video
|
||||
@ -324,19 +455,12 @@
|
||||
- (void)_beginFrame
|
||||
{
|
||||
video_driver_update_viewport(_viewport, NO, _keepAspect);
|
||||
|
||||
assert(!_begin && !_end);
|
||||
_begin = YES;
|
||||
[_context begin];
|
||||
[self _updateUniforms];
|
||||
}
|
||||
|
||||
- (void)_drawViews:(video_frame_info_t *)video_info
|
||||
{
|
||||
assert(_begin && !_end);
|
||||
_begin = NO;
|
||||
_end = YES;
|
||||
|
||||
id<MTLRenderCommandEncoder> rce = _context.rce;
|
||||
|
||||
// draw back buffer
|
||||
@ -358,28 +482,37 @@
|
||||
[_frameView drawWithEncoder:rce];
|
||||
}
|
||||
[rce popDebugGroup];
|
||||
|
||||
if (_menu.enabled && _menu.hasFrame)
|
||||
{
|
||||
[_menu.view drawWithContext:_context];
|
||||
[rce setVertexBytes:&_uniforms length:sizeof(_uniforms) atIndex:BufferIndexUniforms];
|
||||
[rce setRenderPipelineState:_t_pipelineState];
|
||||
if (_menu.view.filter == RTextureFilterNearest)
|
||||
{
|
||||
[rce setFragmentSamplerState:_samplerStateNearest atIndex:SamplerIndexDraw];
|
||||
}
|
||||
else
|
||||
{
|
||||
[rce setFragmentSamplerState:_samplerStateLinear atIndex:SamplerIndexDraw];
|
||||
}
|
||||
[_menu.view drawWithEncoder:rce];
|
||||
}
|
||||
|
||||
#if defined(HAVE_MENU)
|
||||
if (_menu.enabled)
|
||||
{
|
||||
MTLViewport viewport = {
|
||||
.originX = 0.0f,
|
||||
.originY = 0.0f,
|
||||
.width = _viewport->full_width,
|
||||
.height = _viewport->full_height,
|
||||
.znear = 0.0f,
|
||||
.zfar = 1.0,
|
||||
};
|
||||
[rce setViewport:viewport];
|
||||
[rce pushDebugGroup:@"menu"];
|
||||
menu_driver_frame(video_info);
|
||||
|
||||
if (_menu.hasFrame)
|
||||
{
|
||||
[_menu.view drawWithContext:_context];
|
||||
[rce setVertexBytes:&_uniforms length:sizeof(_uniforms) atIndex:BufferIndexUniforms];
|
||||
[rce setRenderPipelineState:_t_pipelineState];
|
||||
if (_menu.view.filter == RTextureFilterNearest)
|
||||
{
|
||||
[rce setFragmentSamplerState:_samplerStateNearest atIndex:SamplerIndexDraw];
|
||||
}
|
||||
else
|
||||
{
|
||||
[rce setFragmentSamplerState:_samplerStateLinear atIndex:SamplerIndexDraw];
|
||||
}
|
||||
[_menu.view drawWithEncoder:rce];
|
||||
}
|
||||
[rce popDebugGroup];
|
||||
}
|
||||
#endif
|
||||
@ -387,8 +520,6 @@
|
||||
|
||||
- (void)_endFrame
|
||||
{
|
||||
assert(!_begin && _end);
|
||||
_end = NO;
|
||||
[_context end];
|
||||
}
|
||||
|
||||
@ -402,18 +533,16 @@
|
||||
return &_viewportMVP;
|
||||
}
|
||||
|
||||
- (Uniforms *)viewportMVPNormalized
|
||||
{
|
||||
return &_viewportMVPNormalized;
|
||||
}
|
||||
|
||||
#pragma mark - MTKViewDelegate
|
||||
|
||||
- (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size
|
||||
{
|
||||
_viewport->full_width = (unsigned int)size.width;
|
||||
_viewport->full_height = (unsigned int)size.height;
|
||||
video_driver_set_size(&_viewport->full_width, &_viewport->full_height);
|
||||
_layer.drawableSize = size;
|
||||
video_driver_update_viewport(_viewport, NO, _keepAspect);
|
||||
|
||||
_viewportMVP.outputSize = simd_make_float2(_viewport->full_width, _viewport->full_height);
|
||||
_viewportMVP.projectionMatrix = matrix_proj_ortho(0, _viewport->full_width, _viewport->full_height, 0);
|
||||
[self _updateViewport:size];
|
||||
}
|
||||
|
||||
- (void)drawInMTKView:(MTKView *)view
|
||||
@ -870,7 +999,6 @@ static vertex_t vertex_bytes[] = {
|
||||
id<MTLCommandBuffer> cb = ctx.blitCommandBuffer;
|
||||
|
||||
MTLRenderPassDescriptor *rpd = [MTLRenderPassDescriptor new];
|
||||
// rpd.colorAttachments[0].clearColor = MTLClearColorMake(0, 0, 0, 1.0);
|
||||
rpd.colorAttachments[0].loadAction = MTLLoadActionDontCare;
|
||||
rpd.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
@interface MetalRaster : NSObject
|
||||
{
|
||||
__weak MetalDriver *_driver;
|
||||
const font_renderer_driver_t *_font_driver;
|
||||
void *_font_data;
|
||||
struct font_atlas *_atlas;
|
||||
@ -44,36 +45,25 @@
|
||||
unsigned _vertices;
|
||||
}
|
||||
|
||||
@property (weak, readwrite) MetalDriver *metal;
|
||||
@property (readonly) struct font_atlas *atlas;
|
||||
@property (readwrite) bool needsUpdate;
|
||||
|
||||
- (instancetype)initWithDriver:(MetalDriver *)metal fontPath:(const char *)font_path fontSize:(unsigned)font_size;
|
||||
- (instancetype)initWithDriver:(MetalDriver *)driver fontPath:(const char *)font_path fontSize:(unsigned)font_size;
|
||||
|
||||
- (int)getWidthForMessage:(const char *)msg length:(unsigned int)length scale:(float)scale;
|
||||
- (int)getWidthForMessage:(const char *)msg length:(NSUInteger)length scale:(float)scale;
|
||||
- (const struct font_glyph *)getGlyph:(uint32_t)code;
|
||||
@end
|
||||
|
||||
@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
|
||||
- (instancetype)initWithDriver:(MetalDriver *)driver fontPath:(const char *)font_path fontSize:(unsigned)font_size
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
if (metal == nil)
|
||||
if (driver == nil)
|
||||
return nil;
|
||||
|
||||
_metal = metal;
|
||||
_context = metal.context;
|
||||
_driver = driver;
|
||||
_context = driver.context;
|
||||
if (!font_renderer_create_default((const void **)&_font_driver,
|
||||
&_font_data, font_path, font_size))
|
||||
{
|
||||
@ -83,7 +73,7 @@ static const NSUInteger kConstantAlignment = 4;
|
||||
|
||||
_uniforms.projectionMatrix = matrix_proj_ortho(0, 1, 0, 1);
|
||||
_atlas = _font_driver->get_atlas(_font_data);
|
||||
_stride = ALIGN_CONSTANTS(_atlas->width);
|
||||
_stride = MTL_ALIGN_BUFFER(_atlas->width);
|
||||
if (_stride == _atlas->width)
|
||||
{
|
||||
_buffer = [_context.device newBufferWithBytes:_atlas->buffer
|
||||
@ -115,7 +105,6 @@ static const NSUInteger kConstantAlignment = 4;
|
||||
_capacity = 12000;
|
||||
_vert = [_context.device newBufferWithLength:sizeof(SpriteVertex) *
|
||||
_capacity options:MTLResourceStorageModeManaged];
|
||||
_needsUpdate = true;
|
||||
if (![self _initializeState])
|
||||
{
|
||||
return nil;
|
||||
@ -188,15 +177,14 @@ static const NSUInteger kConstantAlignment = 4;
|
||||
[_buffer didModifyRange:NSMakeRange(offset, len)];
|
||||
|
||||
_atlas->dirty = false;
|
||||
_needsUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
- (int)getWidthForMessage:(const char *)msg length:(unsigned int)length scale:(float)scale
|
||||
- (int)getWidthForMessage:(const char *)msg length:(NSUInteger)length scale:(float)scale
|
||||
{
|
||||
int delta_x = 0;
|
||||
|
||||
for (unsigned i = 0; i < length; i++)
|
||||
for (NSUInteger 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 ... */
|
||||
@ -262,14 +250,14 @@ static INLINE void write_quad6(SpriteVertex *pv,
|
||||
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 x = (int)roundf(posX * _driver.viewport->full_width);
|
||||
int y = (int)roundf((1.0f - posY) * _driver.viewport->full_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_height = 1.0f / _metal.viewport->height;
|
||||
float inv_win_width = 1.0f / _driver.viewport->full_width;
|
||||
float inv_win_height = 1.0f / _driver.viewport->full_height;
|
||||
|
||||
switch (aligned)
|
||||
{
|
||||
@ -335,8 +323,19 @@ static INLINE void write_quad6(SpriteVertex *pv,
|
||||
|
||||
id<MTLRenderCommandEncoder> rce = _context.rce;
|
||||
[rce pushDebugGroup:@"render fonts"];
|
||||
|
||||
MTLViewport vp = {
|
||||
.originX = 0,
|
||||
.originY = 0,
|
||||
.width = _driver.viewport->full_width,
|
||||
.height = _driver.viewport->full_height,
|
||||
.znear = 0,
|
||||
.zfar = 1,
|
||||
};
|
||||
[rce setViewport:vp];
|
||||
|
||||
[rce setRenderPipelineState:_state];
|
||||
[rce setVertexBytes:&_uniforms length:sizeof(_uniforms) atIndex:BufferIndexUniforms];
|
||||
[rce setVertexBytes:&_uniforms length:sizeof(Uniforms) atIndex:BufferIndexUniforms];
|
||||
[rce setVertexBuffer:_vert offset:start atIndex:BufferIndexPositions];
|
||||
[rce setFragmentTexture:_texture atIndex:TextureIndexColor];
|
||||
[rce setFragmentSamplerState:_sampler atIndex:SamplerIndexDraw];
|
||||
@ -386,7 +385,7 @@ static INLINE void write_quad6(SpriteVertex *pv,
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned msg_len = strlen(msg);
|
||||
NSUInteger msg_len = strlen(msg);
|
||||
[self _renderLine:msg
|
||||
video:video
|
||||
length:msg_len
|
||||
|
@ -35,7 +35,7 @@ static void *menu_display_metal_get_default_mvp(video_frame_info_t *video_info)
|
||||
if (!md)
|
||||
return NULL;
|
||||
|
||||
return (void *)md.viewportMVP;
|
||||
return (void *)&md.viewportMVPNormalized->projectionMatrix;
|
||||
}
|
||||
|
||||
static void menu_display_metal_blend_begin(video_frame_info_t *video_info)
|
||||
|
@ -16,7 +16,7 @@ LIBRARY_SEARCH_PATHS[sdk=macosx*] = $(inherited) $(VULKAN_FRAMEWORK_PATH)
|
||||
|
||||
// OTHER_LDFLAGS = $(inherited) -lMoltenVK -framework MoltenVK
|
||||
|
||||
OTHER_CFLAGS = $(inherited) -DHAVE_RUNAHEAD -DHAVE_GRIFFIN -DHAVE_FLAC -DHAVE_DR_FLAC -DHAVE_DR_MP3 -DHAVE_LROUND -DFLAC__HAS_OGG=0 -DHAVE_CHD -DHAVE_STB_VORBIS -DHAVE_MINIUPNPC -DHAVE_BUILTINMINIUPNPC -DHAVE_UPDATE_ASSETS -DHAVE_LANGEXTRA -DHAVE_CHEEVOS -DHAVE_IMAGEVIEWER -DHAVE_IOHIDMANAGER -DHAVE_CORETEXT -DHAVE_RGUI -DHAVE_MENU -DOSX -DHAVE_OPENGL -DHAVE_CC_RESAMPLER -DHAVE_GLSL -DINLINE=inline -D__LIBRETRO__ -DHAVE_COREAUDIO -DHAVE_DYNAMIC -DHAVE_OVERLAY -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DHAVE_COCOA -DHAVE_MAIN -DHAVE_NETWORKGAMEPAD -DHAVE_NETWORKING -DRARCH_INTERNAL -DHAVE_THREADS -DHAVE_DYLIB -DHAVE_7ZIP -DHAVE_MATERIALUI -DHAVE_HID -DHAVE_XMB -DHAVE_SEGA -DHAVE_SHADERPIPELINE -DHAVE_MMAP -DHAVE_LIBRETRODB -DHAVE_GETOPT_LONG -DHAVE_METAL -DHAVE_SLANG -DHAVE_GLSLANG -DHAVE_SPIRV_CROSS -DWANT_GLSLANG -DENABLE_HLSL -DGLSLANG_OSINCLUDE_UNIX
|
||||
OTHER_CFLAGS = $(inherited) -DHAVE_RUNAHEAD -DHAVE_GRIFFIN -DHAVE_FLAC -DHAVE_DR_FLAC -DHAVE_DR_MP3 -DHAVE_LROUND -DFLAC__HAS_OGG=0 -DHAVE_CHD -DHAVE_STB_VORBIS -DHAVE_MINIUPNPC -DHAVE_BUILTINMINIUPNPC -DHAVE_UPDATE_ASSETS -DHAVE_LANGEXTRA -DHAVE_CHEEVOS -DHAVE_IMAGEVIEWER -DHAVE_IOHIDMANAGER -DHAVE_CORETEXT -DHAVE_RGUI -DHAVE_MENU -DOSX -DHAVE_OPENGL -DHAVE_CC_RESAMPLER -DHAVE_GLSL -DINLINE=inline -D__LIBRETRO__ -DHAVE_COREAUDIO -DHAVE_DYNAMIC -DHAVE_OVERLAY -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DHAVE_COCOA -DHAVE_MAIN -DHAVE_NETWORKGAMEPAD -DHAVE_NETWORKING -DRARCH_INTERNAL -DHAVE_THREADS -DHAVE_DYLIB -DHAVE_7ZIP -DHAVE_MATERIALUI -DHAVE_HID -DHAVE_XMB -DHAVE_SEGA -DHAVE_SHADERPIPELINE -DHAVE_MMAP -DHAVE_LIBRETRODB -DHAVE_GETOPT_LONG -DHAVE_METAL -DHAVE_SLANG -DHAVE_GLSLANG -DHAVE_SPIRV_CROSS -DWANT_GLSLANG -DENABLE_HLSL -DGLSLANG_OSINCLUDE_UNIX -DMETAL_DEBUG
|
||||
|
||||
SRCBASE = $(SRCROOT)/../..
|
||||
DEPS_DIR = $(SRCBASE)/deps
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
05269A6220ABF20500C29F1E /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05269A6120ABF20500C29F1E /* MetalKit.framework */; };
|
||||
05770B9920E805160013DABC /* menu_pipeline.metal in Sources */ = {isa = PBXBuildFile; fileRef = 05770B9820E805160013DABC /* menu_pipeline.metal */; };
|
||||
05A8C7B420DB75A500FF7857 /* Shaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = 05A8C74E20DB72F100FF7857 /* Shaders.metal */; };
|
||||
05A8E23820A63CB40084ABDA /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05A8E23720A63CB40084ABDA /* Metal.framework */; };
|
||||
05A8E23A20A63CED0084ABDA /* IOSurface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05A8E23920A63CED0084ABDA /* IOSurface.framework */; };
|
||||
@ -70,6 +71,7 @@
|
||||
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>"; };
|
||||
05770B9820E805160013DABC /* menu_pipeline.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = menu_pipeline.metal; 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>"; };
|
||||
@ -826,7 +828,6 @@
|
||||
children = (
|
||||
05A8C64120DB72F000FF7857 /* d3d_shaders */,
|
||||
05A8C60020DB72F000FF7857 /* gl_shaders */,
|
||||
05A8C7B320DB756F00FF7857 /* metal_shaders */,
|
||||
05A8C62220DB72F000FF7857 /* vulkan_shaders */,
|
||||
05A8C63E20DB72F000FF7857 /* d3d10.c */,
|
||||
05A8C5F020DB72F000FF7857 /* gl.c */,
|
||||
@ -876,33 +877,33 @@
|
||||
05A8C62220DB72F000FF7857 /* vulkan_shaders */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
05A8C62320DB72F000FF7857 /* pipeline_snow_simple.vert */,
|
||||
05A8C62420DB72F000FF7857 /* opaque.vert */,
|
||||
05A8C62520DB72F000FF7857 /* alpha_blend.frag */,
|
||||
05A8C62620DB72F000FF7857 /* pipeline_snow.frag */,
|
||||
05A8C62720DB72F000FF7857 /* pipeline_ribbon.vert */,
|
||||
05A8C62820DB72F000FF7857 /* opaque.vert.inc */,
|
||||
05A8C62920DB72F000FF7857 /* alpha_blend.frag.inc */,
|
||||
05A8C62A20DB72F000FF7857 /* pipeline_ribbon.frag.inc */,
|
||||
05A8C62B20DB72F000FF7857 /* Makefile */,
|
||||
05A8C62C20DB72F000FF7857 /* pipeline_bokeh.frag.inc */,
|
||||
05A8C62D20DB72F000FF7857 /* font.frag.inc */,
|
||||
05A8C62E20DB72F000FF7857 /* pipeline_snow.frag.inc */,
|
||||
05A8C62F20DB72F000FF7857 /* pipeline_ribbon_simple.vert */,
|
||||
05A8C63020DB72F000FF7857 /* pipeline_snow_simple.frag.inc */,
|
||||
05A8C63120DB72F000FF7857 /* pipeline_ribbon_simple.frag.inc */,
|
||||
05A8C63220DB72F000FF7857 /* pipeline_ribbon_simple.vert.inc */,
|
||||
05A8C63320DB72F000FF7857 /* pipeline_ribbon.frag */,
|
||||
05A8C63420DB72F000FF7857 /* pipeline_snow_simple.vert.inc */,
|
||||
05A8C62520DB72F000FF7857 /* alpha_blend.frag */,
|
||||
05A8C63520DB72F000FF7857 /* font.frag */,
|
||||
05A8C63620DB72F000FF7857 /* alpha_blend.vert */,
|
||||
05A8C63720DB72F000FF7857 /* pipeline_snow_simple.frag */,
|
||||
05A8C63820DB72F000FF7857 /* opaque.frag */,
|
||||
05A8C63920DB72F000FF7857 /* pipeline_ribbon.vert.inc */,
|
||||
05A8C63A20DB72F000FF7857 /* alpha_blend.vert.inc */,
|
||||
05A8C63B20DB72F000FF7857 /* opaque.frag.inc */,
|
||||
05A8C63C20DB72F000FF7857 /* pipeline_bokeh.frag */,
|
||||
05A8C63D20DB72F000FF7857 /* pipeline_ribbon_simple.frag */,
|
||||
05A8C63320DB72F000FF7857 /* pipeline_ribbon.frag */,
|
||||
05A8C63720DB72F000FF7857 /* pipeline_snow_simple.frag */,
|
||||
05A8C62620DB72F000FF7857 /* pipeline_snow.frag */,
|
||||
05A8C62920DB72F000FF7857 /* alpha_blend.frag.inc */,
|
||||
05A8C63A20DB72F000FF7857 /* alpha_blend.vert.inc */,
|
||||
05A8C62D20DB72F000FF7857 /* font.frag.inc */,
|
||||
05A8C63B20DB72F000FF7857 /* opaque.frag.inc */,
|
||||
05A8C62820DB72F000FF7857 /* opaque.vert.inc */,
|
||||
05A8C62C20DB72F000FF7857 /* pipeline_bokeh.frag.inc */,
|
||||
05A8C63120DB72F000FF7857 /* pipeline_ribbon_simple.frag.inc */,
|
||||
05A8C63220DB72F000FF7857 /* pipeline_ribbon_simple.vert.inc */,
|
||||
05A8C62A20DB72F000FF7857 /* pipeline_ribbon.frag.inc */,
|
||||
05A8C63920DB72F000FF7857 /* pipeline_ribbon.vert.inc */,
|
||||
05A8C63020DB72F000FF7857 /* pipeline_snow_simple.frag.inc */,
|
||||
05A8C63420DB72F000FF7857 /* pipeline_snow_simple.vert.inc */,
|
||||
05A8C62E20DB72F000FF7857 /* pipeline_snow.frag.inc */,
|
||||
05A8C63620DB72F000FF7857 /* alpha_blend.vert */,
|
||||
05A8C62420DB72F000FF7857 /* opaque.vert */,
|
||||
05A8C62F20DB72F000FF7857 /* pipeline_ribbon_simple.vert */,
|
||||
05A8C62720DB72F000FF7857 /* pipeline_ribbon.vert */,
|
||||
05A8C62320DB72F000FF7857 /* pipeline_snow_simple.vert */,
|
||||
);
|
||||
path = vulkan_shaders;
|
||||
sourceTree = "<group>";
|
||||
@ -960,6 +961,7 @@
|
||||
05A8C74C20DB72F100FF7857 /* RendererCommon.h */,
|
||||
05A8C75420DB72F100FF7857 /* RendererCommon.m */,
|
||||
05A8C74E20DB72F100FF7857 /* Shaders.metal */,
|
||||
05770B9820E805160013DABC /* menu_pipeline.metal */,
|
||||
05A8C75120DB72F100FF7857 /* ShaderTypes.h */,
|
||||
05A8C74920DB72F100FF7857 /* TexturedView.h */,
|
||||
05A8C75620DB72F100FF7857 /* TexturedView.m */,
|
||||
@ -1029,13 +1031,6 @@
|
||||
path = drivers_font_renderer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
05A8C7B320DB756F00FF7857 /* metal_shaders */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
path = metal_shaders;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
05C5D53220E3DD0900654EE4 /* input */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -1318,6 +1313,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
05D7753720A567A700646447 /* griffin_glslang.cpp in Sources */,
|
||||
05770B9920E805160013DABC /* menu_pipeline.metal in Sources */,
|
||||
05D7753520A567A400646447 /* griffin_cpp.cpp in Sources */,
|
||||
509F0C9D1AA23AFC00619ECC /* griffin_objc.m in Sources */,
|
||||
840222FC1A889EE2009AB261 /* griffin.c in Sources */,
|
||||
|
@ -55,6 +55,11 @@
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isFlipped
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
#endif
|
||||
|
||||
|
@ -297,7 +297,9 @@ static char** waiting_argv;
|
||||
}
|
||||
|
||||
- (void)setVideoMode:(gfx_ctx_mode_t)mode {
|
||||
// TODO(sgc): handle full screen
|
||||
// TODO(sgc): handle full screen?
|
||||
// cheap hack to ensure MTKView posts triggers a drawable resize event
|
||||
[self.window setContentSize:NSMakeSize(mode.width-1, mode.height)];
|
||||
[self.window setContentSize:NSMakeSize(mode.width, mode.height)];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user