Improved AirPlay mirroring

This commit is contained in:
Lior Halphon
2024-08-23 14:20:53 +03:00
parent 795d772c83
commit a7d977a5c5
4 changed files with 86 additions and 1 deletions

View File

@@ -32,5 +32,5 @@ typedef enum {
- (void) createInternalView;
- (uint32_t *)currentBuffer;
- (uint32_t *)previousBuffer;
- (instancetype)mirroredView;
@end

View File

@@ -6,10 +6,13 @@
unsigned _currentBuffer;
GB_frame_blending_mode_t _frameBlendingMode;
bool _oddFrame;
GBViewBase *_parent;
__weak GBViewBase *_child;
}
- (void)screenSizeChanged
{
if (_parent) return;
if (_imageBuffers[0]) free(_imageBuffers[0]);
if (_imageBuffers[1]) free(_imageBuffers[1]);
if (_imageBuffers[2]) free(_imageBuffers[2]);
@@ -23,12 +26,15 @@
- (void)flip
{
if (_parent) return;
_currentBuffer = (_currentBuffer + 1) % self.numberOfBuffers;
_oddFrame = GB_is_odd_frame(_gb);
[_child flip];
}
- (unsigned) numberOfBuffers
{
assert(!_parent);
return _frameBlendingMode? 3 : 2;
}
@@ -39,16 +45,23 @@
- (uint32_t *)currentBuffer
{
if (unlikely(_parent)) {
return [_parent currentBuffer];
}
return _imageBuffers[_currentBuffer];
}
- (uint32_t *)previousBuffer
{
if (unlikely(_parent)) {
return [_parent previousBuffer];
}
return _imageBuffers[(_currentBuffer + 2) % self.numberOfBuffers];
}
- (uint32_t *) pixels
{
assert(!_parent);
return _imageBuffers[(_currentBuffer + 1) % self.numberOfBuffers];
}
@@ -56,10 +69,14 @@
{
_frameBlendingMode = frameBlendingMode;
[self setNeedsDisplay];
[_child setNeedsDisplay];
}
- (GB_frame_blending_mode_t)frameBlendingMode
{
if (unlikely(_parent)) {
return [_parent frameBlendingMode];
}
if (_frameBlendingMode == GB_FRAME_BLENDING_MODE_ACCURATE) {
if (!_gb || GB_is_sgb(_gb)) {
return GB_FRAME_BLENDING_MODE_SIMPLE;
@@ -71,6 +88,7 @@
- (void)dealloc
{
if (_parent) return;
free(_imageBuffers[0]);
free(_imageBuffers[1]);
free(_imageBuffers[2]);
@@ -82,4 +100,22 @@
[self setNeedsDisplay:true];
}
#endif
- (void)setGb:(GB_gameboy_t *)gb
{
assert(!_parent);
_gb = gb;
if (_child) {
_child->_gb = gb;
}
}
- (instancetype)mirroredView
{
if (_child) return _child;
GBViewBase *ret = [[self.class alloc] initWithFrame:self.bounds];
ret->_parent = self;
ret->_gb = _gb;
return _child = ret;
}
@end

View File

@@ -25,6 +25,7 @@ static const vector_float2 rect[] =
vector_float2 _outputResolution;
id<MTLCommandBuffer> _commandBuffer;
bool _waitedForFrame;
_Atomic unsigned _pendingFrames;
}
+ (bool)isSupported
@@ -236,8 +237,11 @@ static const vector_float2 rect[] =
- (void)flip
{
[super flip];
if (_pendingFrames == 2) return;
_pendingFrames++;
dispatch_async(dispatch_get_main_queue(), ^{
[(MTKView *)self.internalView draw];
_pendingFrames--;
});
}

View File

@@ -64,6 +64,9 @@
dispatch_queue_t _cameraQueue;
bool _runModeFromController;
UIWindow *_mirrorWindow;
GBView *_mirrorView;
}
static void loadBootROM(GB_gameboy_t *gb, GB_boot_rom_t type)
@@ -333,9 +336,51 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp)
name:GCControllerDidConnectNotification
object:nil];
for (NSString *name in @[UIScreenDidConnectNotification,
UIScreenDidDisconnectNotification,
UIScreenModeDidChangeNotification]) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateMirrorWindow)
name:name
object:nil];
}
[self updateMirrorWindow];
return true;
}
- (void)updateMirrorWindow
{
if ([UIScreen screens].count == 1) {
_mirrorWindow = nil;
_mirrorView = nil;
return;
}
if (_mirrorWindow && ![[UIScreen screens] containsObject:_mirrorWindow.screen]) {
_mirrorWindow = nil;
_mirrorView = nil;
}
for (UIScreen *screen in [UIScreen screens]) {
if (screen == UIScreen.mainScreen) continue;
CGRect rect = screen.bounds;
rect.size.height = floor(rect.size.height / 144) * 144;
rect.size.width = rect.size.height / 144 * 160;
rect.origin.x = (screen.bounds.size.width - rect.size.width) / 2;
rect.origin.y = (screen.bounds.size.height - rect.size.height) / 2;
_mirrorWindow = [[UIWindow alloc] initWithFrame:screen.bounds];
_mirrorWindow.screen = screen;
_mirrorView = [_gbView mirroredView];
_mirrorView.frame = rect;
_mirrorWindow.backgroundColor = [UIColor blackColor];
[_mirrorWindow addSubview:_mirrorView];
[_mirrorWindow setHidden:false];
break;
}
}
- (void)setControllerHandlers
{