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
{
#if TARGET_OS_IPHONE
return true;
#else
if (MTLCopyAllDevices) {
return [MTLCopyAllDevices() count];
}
return false;
#endif
}
- (void) allocateTextures
@ -135,7 +139,9 @@ static const vector_float2 rect[] =
- (void)drawInMTKView:(MTKView *)view
{
#if !TARGET_OS_IPHONE
if (!(view.window.occlusionState & NSWindowOcclusionStateVisible)) return;
#endif
if (!self.gb) return;
if (texture.width != GB_get_screen_width(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;
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];
*(vector_float2 *)[output_resolution_buffer contents] = output_resolution;
@ -210,10 +216,15 @@ static const vector_float2 rect[] =
{
[super flip];
dispatch_async(dispatch_get_main_queue(), ^{
#if TARGET_OS_IPHONE
[(MTKView *)self.internalView setNeedsDisplay];
#else
[(MTKView *)self.internalView setNeedsDisplay:true];
#endif
});
}
#if !TARGET_OS_IPHONE
- (NSImage *)renderToImage
{
CIImage *ciImage = [CIImage imageWithMTLTexture:[[(MTKView *)self.internalView currentDrawable] texture]
@ -228,5 +239,6 @@ static const vector_float2 rect[] =
CGImageRelease(cgImage);
return ret;
}
#endif
@end

View File

@ -1,32 +1,16 @@
#import <Cocoa/Cocoa.h>
#include <Core/gb.h>
#import <JoyKit/JoyKit.h>
#import "GBOSDView.h"
#import "GBViewBase.h"
@class Document;
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 GBView : NSView<JOYListener>
- (void) flip;
- (uint32_t *) pixels;
@interface GBView : GBViewBase<JOYListener>
@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) bool isRewinding;
@property (nonatomic, strong) NSView *internalView;
@property (weak) GBOSDView *osdView;
- (void) createInternalView;
- (uint32_t *)currentBuffer;
- (uint32_t *)previousBuffer;
- (void)screenSizeChanged;
- (void)setRumble: (double)amp;
- (NSImage *)renderToImage;
- (void)setRumble: (double)amp;
@end

View File

@ -104,8 +104,6 @@ static const uint8_t workboy_vk_to_key[] = {
@implementation GBView
{
uint32_t *image_buffers[3];
unsigned char current_buffer;
bool mouse_hidden;
NSTrackingArea *tracking_area;
bool _mouseHidingEnabled;
@ -116,7 +114,6 @@ static const uint8_t workboy_vk_to_key[] = {
bool analogClockMultiplierValid;
NSEventModifierFlags previousModifiers;
JOYController *lastController;
GB_frame_blending_mode_t _frameBlendingMode;
bool _turbo;
bool _mouseControlEnabled;
}
@ -137,11 +134,6 @@ static const uint8_t workboy_vk_to_key[] = {
return [super allocWithZone:zone];
}
- (void) createInternalView
{
assert(false && "createInternalView must not be inherited");
}
- (void) _init
{
[self registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
@ -162,15 +154,7 @@ static const uint8_t workboy_vk_to_key[] = {
- (void)screenSizeChanged
{
if (image_buffers[0]) free(image_buffers[0]);
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);
[super screenSizeChanged];
dispatch_async(dispatch_get_main_queue(), ^{
[self setFrame:self.superview.frame];
@ -182,33 +166,8 @@ static const uint8_t workboy_vk_to_key[] = {
[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
{
free(image_buffers[0]);
free(image_buffers[1]);
free(image_buffers[2]);
if (mouse_hidden) {
mouse_hidden = false;
[NSCursor unhide];
@ -217,6 +176,7 @@ static const uint8_t workboy_vk_to_key[] = {
[self setRumble:0];
[JOYController unregisterListener:self];
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
if (!(self = [super initWithCoder:coder])) {
@ -301,12 +261,7 @@ static const uint8_t workboy_vk_to_key[] = {
(analogClockMultiplierValid && analogClockMultiplier < 1)) {
[self.osdView displayText:@"Slow motion..."];
}
current_buffer = (current_buffer + 1) % self.numberOfBuffers;
}
- (uint32_t *) pixels
{
return image_buffers[(current_buffer + 1) % self.numberOfBuffers];
[super flip];
}
-(void)keyDown:(NSEvent *)theEvent
@ -760,16 +715,6 @@ static const uint8_t workboy_vk_to_key[] = {
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
{
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 "GBHorizontalLayout.h"
#import "GBVerticalLayout.h"
#import "GBViewMetal.h"
#include <Core/gb.h>
static void positionView(UIImageView *view, CGPoint position)
{
@ -26,6 +28,8 @@ static void positionView(UIImageView *view, CGPoint position)
UIImageView *_bButtonView;
UIImageView *_startButtonView;
UIImageView *_selectButtonView;
GBView *_gbView;
GB_gameboy_t _gb;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
@ -33,36 +37,42 @@ static void positionView(UIImageView *view, CGPoint position)
_window = [[UIWindow alloc] init];
_window.rootViewController = self;
[_window makeKeyAndVisible];
_window.backgroundColor = [UIColor colorWithRed:174 / 255.0 green:176 / 255.0 blue:180 / 255.0 alpha:1.0];
_horizontalLayout = [[GBHorizontalLayout alloc] init];
_verticalLayout = [[GBVerticalLayout alloc] init];
_backgroundView = [[UIImageView alloc] initWithImage:nil];
[_window addSubview:_backgroundView];
self.view = _backgroundView;
_dpadView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"dpad"]];
_aButtonView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"button"]];
_bButtonView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"button"]];
_startButtonView = [[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:_aButtonView];
[_backgroundView addSubview:_bButtonView];
[_backgroundView addSubview:_startButtonView];
[_backgroundView addSubview:_selectButtonView];
[_backgroundView addSubview:_gbView];
[self orientationChange];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(orientationChange)
name:UIApplicationDidChangeStatusBarOrientationNotification
object:nil];
return true;
}
- (void)orientationChange
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration
{
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
_currentLayout = _verticalLayout;
}
@ -78,6 +88,16 @@ static void positionView(UIImageView *view, CGPoint position)
positionView(_bButtonView, _currentLayout.bLocation);
positionView(_startButtonView, _currentLayout.startLocation);
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