Merge pull request #7176 from stuartcarnie/sgc-metal

Metal: Add support for screen shots
This commit is contained in:
Twinaphex 2018-09-03 03:00:36 +02:00 committed by GitHub
commit 9c53dc3797
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 108 additions and 19 deletions

View File

@ -34,6 +34,9 @@ typedef struct
/*! @brief Specifies whether rendering is synchronized with the display */
@property (nonatomic, readwrite) bool displaySyncEnabled;
/*! @brief captureEnabled allows previous frames to be read */
@property (nonatomic, readwrite) bool captureEnabled;
/*! @brief Returns the command buffer used for pre-render work,
* such as mip maps and shader effects
* */
@ -70,4 +73,6 @@ typedef struct
/*! @brief end commits the command buffer */
- (void)end;
- (bool)readBackBuffer:(uint8_t *)buffer;
@end

View File

@ -54,6 +54,9 @@
id<MTLRenderPipelineState> _states[GFX_MAX_SHADERS][2];
id<MTLRenderPipelineState> _clearState;
Uniforms _uniforms;
bool _captureEnabled;
id<MTLTexture> _backBuffer;
}
- (instancetype)initWithDevice:(id<MTLDevice>)d
@ -470,11 +473,65 @@
[_chain[_currentChain] discard];
}
- (void)setCaptureEnabled:(bool)captureEnabled
{
if (_captureEnabled == captureEnabled)
return;
_captureEnabled = captureEnabled;
//_layer.framebufferOnly = !captureEnabled;
}
- (bool)captureEnabled
{
return _captureEnabled;
}
- (bool)readBackBuffer:(uint8_t *)buffer
{
if (!_captureEnabled || _backBuffer == nil)
return NO;
if (_backBuffer.pixelFormat != MTLPixelFormatBGRA8Unorm)
{
RARCH_WARN("[Metal]: unexpected pixel format %d\n", _backBuffer.pixelFormat);
return NO;
}
uint8_t *tmp = malloc(_backBuffer.width * _backBuffer.height * 4);
[_backBuffer getBytes:tmp
bytesPerRow:4 * _backBuffer.width
fromRegion:MTLRegionMake2D(0, 0, _backBuffer.width, _backBuffer.height)
mipmapLevel:0];
NSUInteger srcStride = _backBuffer.width * 4;
uint8_t const *src = tmp + (_viewport.y * srcStride);
NSUInteger dstStride = _viewport.width * 3;
uint8_t *dst = buffer + (_viewport.height - 1) * dstStride;
for (int y = _viewport.y; y < _viewport.height; y++, src += srcStride, dst -= dstStride)
{
for (int x = _viewport.x; x < _viewport.width; x++)
{
dst[3 * x + 0] = src[4 * x + 0];
dst[3 * x + 1] = src[4 * x + 1];
dst[3 * x + 2] = src[4 * x + 2];
}
}
free(tmp);
return YES;
}
- (void)begin
{
assert(_commandBuffer == nil);
dispatch_semaphore_wait(_inflightSemaphore, DISPATCH_TIME_FOREVER);
_commandBuffer = [_commandQueue commandBuffer];
_backBuffer = nil;
}
- (id<MTLRenderCommandEncoder>)rce
@ -486,6 +543,10 @@
rpd.colorAttachments[0].clearColor = _clearColor;
rpd.colorAttachments[0].loadAction = MTLLoadActionClear;
rpd.colorAttachments[0].texture = self.nextDrawable.texture;
if (_captureEnabled)
{
_backBuffer = self.nextDrawable.texture;
}
_rce = [_commandBuffer renderCommandEncoderWithDescriptor:rpd];
}
return _rce;
@ -643,7 +704,7 @@ static const NSUInteger kConstantAlignment = 4;
- (bool)allocRange:(BufferRange *)range length:(NSUInteger)length
{
bzero(range, sizeof(*range));
#if TARGET_OS_OSX
MTLResourceOptions opts = MTLResourceStorageModeManaged;
#else

View File

@ -55,6 +55,12 @@ typedef struct
vector_float2 texCoord METAL_ATTRIBUTE(VertexAttributeTexcoord);
} Vertex;
typedef struct
{
vector_float4 position;
vector_float2 texCoord;
} VertexSlang;
typedef struct
{
vector_float4 position METAL_POSITION;

View File

@ -40,6 +40,7 @@ extern MTLPixelFormat SelectOptimalPixelFormat(MTLPixelFormat fmt);
- (void)setFilteringIndex:(int)index smooth:(bool)smooth;
- (BOOL)setShaderFromPath:(NSString *)path;
- (void)updateFrame:(void const *)src pitch:(NSUInteger)pitch;
- (bool)readViewport:(uint8_t *)buffer isIdle:(bool)isIdle;
@end

View File

@ -546,6 +546,7 @@ typedef struct MTLALIGN(16)
Context *_context;
id<MTLTexture> _texture; // final render texture
Vertex _v[4];
VertexSlang _vertex[4];
CGSize _size; // size of view in pixels
CGRect _frame;
NSUInteger _bpp;
@ -587,6 +588,15 @@ typedef struct MTLALIGN(16)
self.size = d.size;
self.frame = CGRectMake(0, 0, 1, 1);
resize_render_targets = YES;
// init slang vertex buffer
VertexSlang v[4] = {
{simd_make_float4(0, 1, 0, 1), simd_make_float2(0, 1)},
{simd_make_float4(1, 1, 0, 1), simd_make_float2(1, 1)},
{simd_make_float4(0, 0, 0, 1), simd_make_float2(0, 0)},
{simd_make_float4(1, 0, 0, 1), simd_make_float2(1, 0)},
};
memcpy(_vertex, v, sizeof(_vertex));
}
return self;
}
@ -750,6 +760,24 @@ typedef struct MTLALIGN(16)
}
}
- (bool)readViewport:(uint8_t *)buffer isIdle:(bool)isIdle
{
RARCH_LOG("[Metal]: readViewport is_idle = %s\n", isIdle ? "YES" : "NO");
bool enabled = _context.captureEnabled;
if (!enabled)
_context.captureEnabled = YES;
video_driver_cached_frame();
bool res = [_context readBackBuffer:buffer];
if (!enabled)
_context.captureEnabled = NO;
return res;
}
- (void)updateFrame:(void const *)src pitch:(NSUInteger)pitch
{
if (_shader && (_engine.frame.output_size.x != _viewport->width ||
@ -816,19 +844,6 @@ typedef struct MTLALIGN(16)
init_history = NO;
}
typedef struct vertex
{
simd_float4 pos;
simd_float2 tex;
} vertex_t;
static vertex_t vertex_bytes[] = {
{{0, 1, 0, 1}, {0, 1}},
{{1, 1, 0, 1}, {1, 1}},
{{0, 0, 0, 1}, {0, 0}},
{{1, 0, 0, 1}, {1, 0}},
};
- (void)drawWithEncoder:(id<MTLRenderCommandEncoder>)rce
{
if (_texture)
@ -942,7 +957,7 @@ static vertex_t vertex_bytes[] = {
[rce setFragmentTextures:textures withRange:NSMakeRange(0, SLANG_NUM_BINDINGS)];
[rce setFragmentSamplerStates:samplers withRange:NSMakeRange(0, SLANG_NUM_BINDINGS)];
[rce setVertexBytes:vertex_bytes length:sizeof(vertex_bytes) atIndex:4];
[rce setVertexBytes:_vertex length:sizeof(_vertex) atIndex:4];
[rce drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
if (!backBuffer)
@ -1162,13 +1177,13 @@ static vertex_t vertex_bytes[] = {
@try
{
MTLVertexDescriptor *vd = [MTLVertexDescriptor new];
vd.attributes[0].offset = offsetof(vertex_t, pos);
vd.attributes[0].offset = offsetof(VertexSlang, position);
vd.attributes[0].format = MTLVertexFormatFloat4;
vd.attributes[0].bufferIndex = 4;
vd.attributes[1].offset = offsetof(vertex_t, tex);
vd.attributes[1].offset = offsetof(VertexSlang, texCoord);
vd.attributes[1].format = MTLVertexFormatFloat2;
vd.attributes[1].bufferIndex = 4;
vd.layouts[4].stride = sizeof(vertex_t);
vd.layouts[4].stride = sizeof(VertexSlang);
vd.layouts[4].stepFunction = MTLVertexStepFunctionPerVertex;
MTLRenderPipelineDescriptor *psd = [MTLRenderPipelineDescriptor new];

View File

@ -163,7 +163,8 @@ static void metal_viewport_info(void *data, struct video_viewport *vp)
static bool metal_read_viewport(void *data, uint8_t *buffer, bool is_idle)
{
return true;
MetalDriver *md = (__bridge MetalDriver *)data;
return [md.frameView readViewport:buffer isIdle:is_idle];
}
static uintptr_t metal_load_texture(void *video_data, void *data,