Porting GBViewMetal

This commit is contained in:
Lior Halphon 2023-01-13 21:57:57 +02:00
parent 093998389c
commit 4c5d896630
10 changed files with 194 additions and 94 deletions

35
AppleCommon/GBViewBase.h Normal file
View File

@ -0,0 +1,35 @@
#include <TargetConditionals.h>
#include <Core/gb.h>
#if TARGET_OS_IPHONE
#define NSView UIView
#import <UIKit/UIKit.h>
#else
#import <Cocoa/Cocoa.h>
#endif
typedef enum {
GB_FRAME_BLENDING_MODE_DISABLED,
GB_FRAME_BLENDING_MODE_SIMPLE,
GB_FRAME_BLENDING_MODE_ACCURATE,
GB_FRAME_BLENDING_MODE_ACCURATE_EVEN = GB_FRAME_BLENDING_MODE_ACCURATE,
GB_FRAME_BLENDING_MODE_ACCURATE_ODD,
} GB_frame_blending_mode_t;
@interface GBViewBase : NSView
{
@public
GB_gameboy_t *_gb;
}
@property (nonatomic) GB_gameboy_t *gb;
@property (nonatomic) GB_frame_blending_mode_t frameBlendingMode;
@property (nonatomic, strong) NSView *internalView;
- (void) flip;
- (uint32_t *) pixels;
- (void)screenSizeChanged;
- (void) createInternalView;
- (uint32_t *)currentBuffer;
- (uint32_t *)previousBuffer;
@end

83
AppleCommon/GBViewBase.m Normal file
View File

@ -0,0 +1,83 @@
#import "GBViewBase.h"
@implementation GBViewBase
{
uint32_t *_imageBuffers[3];
unsigned _currentBuffer;
GB_frame_blending_mode_t _frameBlendingMode;
}
- (void)screenSizeChanged
{
if (_imageBuffers[0]) free(_imageBuffers[0]);
if (_imageBuffers[1]) free(_imageBuffers[1]);
if (_imageBuffers[2]) free(_imageBuffers[2]);
size_t buffer_size = sizeof(_imageBuffers[0][0]) * GB_get_screen_width(_gb) * GB_get_screen_height(_gb);
_imageBuffers[0] = calloc(1, buffer_size);
_imageBuffers[1] = calloc(1, buffer_size);
_imageBuffers[2] = calloc(1, buffer_size);
}
- (void)flip
{
_currentBuffer = (_currentBuffer + 1) % self.numberOfBuffers;
}
- (unsigned) numberOfBuffers
{
return _frameBlendingMode? 3 : 2;
}
- (void) createInternalView
{
assert(false && "createInternalView must not be inherited");
}
- (uint32_t *)currentBuffer
{
return _imageBuffers[_currentBuffer];
}
- (uint32_t *)previousBuffer
{
return _imageBuffers[(_currentBuffer + 2) % self.numberOfBuffers];
}
- (uint32_t *) pixels
{
return _imageBuffers[(_currentBuffer + 1) % self.numberOfBuffers];
}
- (void) setFrameBlendingMode:(GB_frame_blending_mode_t)frameBlendingMode
{
_frameBlendingMode = frameBlendingMode;
[self setNeedsDisplay];
}
- (GB_frame_blending_mode_t)frameBlendingMode
{
if (_frameBlendingMode == GB_FRAME_BLENDING_MODE_ACCURATE) {
if (!_gb || GB_is_sgb(_gb)) {
return GB_FRAME_BLENDING_MODE_SIMPLE;
}
return GB_is_odd_frame(_gb)? GB_FRAME_BLENDING_MODE_ACCURATE_ODD : GB_FRAME_BLENDING_MODE_ACCURATE_EVEN;
}
return _frameBlendingMode;
}
- (void)dealloc
{
free(_imageBuffers[0]);
free(_imageBuffers[1]);
free(_imageBuffers[2]);
}
#if !TARGET_OS_IPHONE
- (void)setNeedsDisplay
{
[self setNeedsDisplay:true];
}
#endif
@end

11
AppleCommon/GBViewMetal.h Normal file
View File

@ -0,0 +1,11 @@
#include <TargetConditionals.h>
#import <MetalKit/MetalKit.h>
#if TARGET_OS_IPHONE
#import "../iOS/GBView.h"
#else
#import "../Cocoa/GBView.h"
#endif
@interface GBViewMetal : GBView<MTKViewDelegate>
+ (bool) isSupported;
@end

View File

@ -25,10 +25,14 @@ static const vector_float2 rect[] =
+ (bool)isSupported + (bool)isSupported
{ {
#if TARGET_OS_IPHONE
return true;
#else
if (MTLCopyAllDevices) { if (MTLCopyAllDevices) {
return [MTLCopyAllDevices() count]; return [MTLCopyAllDevices() count];
} }
return false; return false;
#endif
} }
- (void) allocateTextures - (void) allocateTextures
@ -135,7 +139,9 @@ static const vector_float2 rect[] =
- (void)drawInMTKView:(MTKView *)view - (void)drawInMTKView:(MTKView *)view
{ {
#if !TARGET_OS_IPHONE
if (!(view.window.occlusionState & NSWindowOcclusionStateVisible)) return; if (!(view.window.occlusionState & NSWindowOcclusionStateVisible)) return;
#endif
if (!self.gb) return; if (!self.gb) return;
if (texture.width != GB_get_screen_width(self.gb) || if (texture.width != GB_get_screen_width(self.gb) ||
texture.height != GB_get_screen_height(self.gb)) { texture.height != GB_get_screen_height(self.gb)) {
@ -161,7 +167,7 @@ static const vector_float2 rect[] =
MTLRenderPassDescriptor *render_pass_descriptor = view.currentRenderPassDescriptor; MTLRenderPassDescriptor *render_pass_descriptor = view.currentRenderPassDescriptor;
id<MTLCommandBuffer> command_buffer = [command_queue commandBuffer]; id<MTLCommandBuffer> command_buffer = [command_queue commandBuffer];
if (render_pass_descriptor != nil) { if (render_pass_descriptor) {
*(GB_frame_blending_mode_t *)[frame_blending_mode_buffer contents] = [self frameBlendingMode]; *(GB_frame_blending_mode_t *)[frame_blending_mode_buffer contents] = [self frameBlendingMode];
*(vector_float2 *)[output_resolution_buffer contents] = output_resolution; *(vector_float2 *)[output_resolution_buffer contents] = output_resolution;
@ -210,10 +216,15 @@ static const vector_float2 rect[] =
{ {
[super flip]; [super flip];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
#if TARGET_OS_IPHONE
[(MTKView *)self.internalView setNeedsDisplay];
#else
[(MTKView *)self.internalView setNeedsDisplay:true]; [(MTKView *)self.internalView setNeedsDisplay:true];
#endif
}); });
} }
#if !TARGET_OS_IPHONE
- (NSImage *)renderToImage - (NSImage *)renderToImage
{ {
CIImage *ciImage = [CIImage imageWithMTLTexture:[[(MTKView *)self.internalView currentDrawable] texture] CIImage *ciImage = [CIImage imageWithMTLTexture:[[(MTKView *)self.internalView currentDrawable] texture]
@ -228,5 +239,6 @@ static const vector_float2 rect[] =
CGImageRelease(cgImage); CGImageRelease(cgImage);
return ret; return ret;
} }
#endif
@end @end

View File

@ -1,32 +1,16 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#include <Core/gb.h>
#import <JoyKit/JoyKit.h> #import <JoyKit/JoyKit.h>
#import "GBOSDView.h" #import "GBOSDView.h"
#import "GBViewBase.h"
@class Document; @class Document;
typedef enum { @interface GBView : GBViewBase<JOYListener>
GB_FRAME_BLENDING_MODE_DISABLED,
GB_FRAME_BLENDING_MODE_SIMPLE,
GB_FRAME_BLENDING_MODE_ACCURATE,
GB_FRAME_BLENDING_MODE_ACCURATE_EVEN = GB_FRAME_BLENDING_MODE_ACCURATE,
GB_FRAME_BLENDING_MODE_ACCURATE_ODD,
} GB_frame_blending_mode_t;
@interface GBView : NSView<JOYListener>
- (void) flip;
- (uint32_t *) pixels;
@property (nonatomic, weak) IBOutlet Document *document; @property (nonatomic, weak) IBOutlet Document *document;
@property (nonatomic) GB_gameboy_t *gb;
@property (nonatomic) GB_frame_blending_mode_t frameBlendingMode;
@property (nonatomic, getter=isMouseHidingEnabled) bool mouseHidingEnabled; @property (nonatomic, getter=isMouseHidingEnabled) bool mouseHidingEnabled;
@property (nonatomic) bool isRewinding; @property (nonatomic) bool isRewinding;
@property (nonatomic, strong) NSView *internalView;
@property (weak) GBOSDView *osdView; @property (weak) GBOSDView *osdView;
- (void) createInternalView;
- (uint32_t *)currentBuffer;
- (uint32_t *)previousBuffer;
- (void)screenSizeChanged;
- (void)setRumble: (double)amp;
- (NSImage *)renderToImage; - (NSImage *)renderToImage;
- (void)setRumble: (double)amp;
@end @end

View File

@ -104,8 +104,6 @@ static const uint8_t workboy_vk_to_key[] = {
@implementation GBView @implementation GBView
{ {
uint32_t *image_buffers[3];
unsigned char current_buffer;
bool mouse_hidden; bool mouse_hidden;
NSTrackingArea *tracking_area; NSTrackingArea *tracking_area;
bool _mouseHidingEnabled; bool _mouseHidingEnabled;
@ -116,7 +114,6 @@ static const uint8_t workboy_vk_to_key[] = {
bool analogClockMultiplierValid; bool analogClockMultiplierValid;
NSEventModifierFlags previousModifiers; NSEventModifierFlags previousModifiers;
JOYController *lastController; JOYController *lastController;
GB_frame_blending_mode_t _frameBlendingMode;
bool _turbo; bool _turbo;
bool _mouseControlEnabled; bool _mouseControlEnabled;
} }
@ -137,11 +134,6 @@ static const uint8_t workboy_vk_to_key[] = {
return [super allocWithZone:zone]; return [super allocWithZone:zone];
} }
- (void) createInternalView
{
assert(false && "createInternalView must not be inherited");
}
- (void) _init - (void) _init
{ {
[self registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, nil]]; [self registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
@ -162,15 +154,7 @@ static const uint8_t workboy_vk_to_key[] = {
- (void)screenSizeChanged - (void)screenSizeChanged
{ {
if (image_buffers[0]) free(image_buffers[0]); [super screenSizeChanged];
if (image_buffers[1]) free(image_buffers[1]);
if (image_buffers[2]) free(image_buffers[2]);
size_t buffer_size = sizeof(image_buffers[0][0]) * GB_get_screen_width(_gb) * GB_get_screen_height(_gb);
image_buffers[0] = calloc(1, buffer_size);
image_buffers[1] = calloc(1, buffer_size);
image_buffers[2] = calloc(1, buffer_size);
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self setFrame:self.superview.frame]; [self setFrame:self.superview.frame];
@ -182,33 +166,8 @@ static const uint8_t workboy_vk_to_key[] = {
[self setFrame:self.superview.frame]; [self setFrame:self.superview.frame];
} }
- (void) setFrameBlendingMode:(GB_frame_blending_mode_t)frameBlendingMode
{
_frameBlendingMode = frameBlendingMode;
[self setNeedsDisplay:true];
}
- (GB_frame_blending_mode_t)frameBlendingMode
{
if (_frameBlendingMode == GB_FRAME_BLENDING_MODE_ACCURATE) {
if (!_gb || GB_is_sgb(_gb)) {
return GB_FRAME_BLENDING_MODE_SIMPLE;
}
return GB_is_odd_frame(_gb)? GB_FRAME_BLENDING_MODE_ACCURATE_ODD : GB_FRAME_BLENDING_MODE_ACCURATE_EVEN;
}
return _frameBlendingMode;
}
- (unsigned char) numberOfBuffers
{
return _frameBlendingMode? 3 : 2;
}
- (void)dealloc - (void)dealloc
{ {
free(image_buffers[0]);
free(image_buffers[1]);
free(image_buffers[2]);
if (mouse_hidden) { if (mouse_hidden) {
mouse_hidden = false; mouse_hidden = false;
[NSCursor unhide]; [NSCursor unhide];
@ -217,6 +176,7 @@ static const uint8_t workboy_vk_to_key[] = {
[self setRumble:0]; [self setRumble:0];
[JOYController unregisterListener:self]; [JOYController unregisterListener:self];
} }
- (instancetype)initWithCoder:(NSCoder *)coder - (instancetype)initWithCoder:(NSCoder *)coder
{ {
if (!(self = [super initWithCoder:coder])) { if (!(self = [super initWithCoder:coder])) {
@ -301,12 +261,7 @@ static const uint8_t workboy_vk_to_key[] = {
(analogClockMultiplierValid && analogClockMultiplier < 1)) { (analogClockMultiplierValid && analogClockMultiplier < 1)) {
[self.osdView displayText:@"Slow motion..."]; [self.osdView displayText:@"Slow motion..."];
} }
current_buffer = (current_buffer + 1) % self.numberOfBuffers; [super flip];
}
- (uint32_t *) pixels
{
return image_buffers[(current_buffer + 1) % self.numberOfBuffers];
} }
-(void)keyDown:(NSEvent *)theEvent -(void)keyDown:(NSEvent *)theEvent
@ -760,16 +715,6 @@ static const uint8_t workboy_vk_to_key[] = {
previousModifiers = event.modifierFlags; previousModifiers = event.modifierFlags;
} }
- (uint32_t *)currentBuffer
{
return image_buffers[current_buffer];
}
- (uint32_t *)previousBuffer
{
return image_buffers[(current_buffer + 2) % self.numberOfBuffers];
}
-(NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender -(NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
{ {
NSPasteboard *pboard = [sender draggingPasteboard]; NSPasteboard *pboard = [sender draggingPasteboard];

View File

@ -1,7 +0,0 @@
#import <Cocoa/Cocoa.h>
#import <MetalKit/MetalKit.h>
#import "GBView.h"
@interface GBViewMetal : GBView<MTKViewDelegate>
+ (bool) isSupported;
@end

5
iOS/GBView.h Normal file
View File

@ -0,0 +1,5 @@
#import "GBViewBase.h"
@interface GBView : GBViewBase
@end

12
iOS/GBView.m Normal file
View File

@ -0,0 +1,12 @@
#import "GBView.h"
@implementation GBView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
[self createInternalView];
[self addSubview:self.internalView];
self.internalView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
return self;
}
@end

View File

@ -1,6 +1,8 @@
#import "GBViewController.h" #import "GBViewController.h"
#import "GBHorizontalLayout.h" #import "GBHorizontalLayout.h"
#import "GBVerticalLayout.h" #import "GBVerticalLayout.h"
#import "GBViewMetal.h"
#include <Core/gb.h>
static void positionView(UIImageView *view, CGPoint position) static void positionView(UIImageView *view, CGPoint position)
{ {
@ -26,6 +28,8 @@ static void positionView(UIImageView *view, CGPoint position)
UIImageView *_bButtonView; UIImageView *_bButtonView;
UIImageView *_startButtonView; UIImageView *_startButtonView;
UIImageView *_selectButtonView; UIImageView *_selectButtonView;
GBView *_gbView;
GB_gameboy_t _gb;
} }
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
@ -33,36 +37,42 @@ static void positionView(UIImageView *view, CGPoint position)
_window = [[UIWindow alloc] init]; _window = [[UIWindow alloc] init];
_window.rootViewController = self; _window.rootViewController = self;
[_window makeKeyAndVisible]; [_window makeKeyAndVisible];
_window.backgroundColor = [UIColor colorWithRed:174 / 255.0 green:176 / 255.0 blue:180 / 255.0 alpha:1.0];
_horizontalLayout = [[GBHorizontalLayout alloc] init]; _horizontalLayout = [[GBHorizontalLayout alloc] init];
_verticalLayout = [[GBVerticalLayout alloc] init]; _verticalLayout = [[GBVerticalLayout alloc] init];
_backgroundView = [[UIImageView alloc] initWithImage:nil]; _backgroundView = [[UIImageView alloc] initWithImage:nil];
[_window addSubview:_backgroundView]; [_window addSubview:_backgroundView];
self.view = _backgroundView;
_dpadView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"dpad"]]; _dpadView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"dpad"]];
_aButtonView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"button"]]; _aButtonView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"button"]];
_bButtonView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"button"]]; _bButtonView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"button"]];
_startButtonView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"button2"]]; _startButtonView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"button2"]];
_selectButtonView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"button2"]]; _selectButtonView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"button2"]];
_gbView = [[GBViewMetal alloc] initWithFrame:CGRectZero];
GB_init(&_gb, GB_MODEL_CGB_E);
_gbView.gb = &_gb;
[_gbView screenSizeChanged];
[self willRotateToInterfaceOrientation:[UIApplication sharedApplication].statusBarOrientation
duration:0];
[_backgroundView addSubview:_dpadView]; [_backgroundView addSubview:_dpadView];
[_backgroundView addSubview:_aButtonView]; [_backgroundView addSubview:_aButtonView];
[_backgroundView addSubview:_bButtonView]; [_backgroundView addSubview:_bButtonView];
[_backgroundView addSubview:_startButtonView]; [_backgroundView addSubview:_startButtonView];
[_backgroundView addSubview:_selectButtonView]; [_backgroundView addSubview:_selectButtonView];
[_backgroundView addSubview:_gbView];
[self orientationChange];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(orientationChange)
name:UIApplicationDidChangeStatusBarOrientationNotification
object:nil];
return true; return true;
} }
- (void)orientationChange - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration
{ {
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) { if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
_currentLayout = _verticalLayout; _currentLayout = _verticalLayout;
} }
@ -78,6 +88,16 @@ static void positionView(UIImageView *view, CGPoint position)
positionView(_bButtonView, _currentLayout.bLocation); positionView(_bButtonView, _currentLayout.bLocation);
positionView(_startButtonView, _currentLayout.startLocation); positionView(_startButtonView, _currentLayout.startLocation);
positionView(_selectButtonView, _currentLayout.selectLocation); positionView(_selectButtonView, _currentLayout.selectLocation);
CGRect screenFrame = _currentLayout.screenRect;
screenFrame.origin.x /= [UIScreen mainScreen].scale;
screenFrame.origin.y /= [UIScreen mainScreen].scale;
screenFrame.size.width /= [UIScreen mainScreen].scale;
screenFrame.size.height /= [UIScreen mainScreen].scale;
_gbView.frame = screenFrame;
memset(_gbView.pixels, rand(), 160 * 144 * 4);
[_gbView flip];
} }
- (BOOL)prefersHomeIndicatorAutoHidden - (BOOL)prefersHomeIndicatorAutoHidden