Basic Metal support. No OpenGL fallback, no shaders, no blending.
This commit is contained in:
parent
9a3d53ae51
commit
5b39cacc8a
@ -1,6 +1,7 @@
|
|||||||
#import <Carbon/Carbon.h>
|
#import <Carbon/Carbon.h>
|
||||||
#import "GBView.h"
|
#import "GBView.h"
|
||||||
#import "GBViewGL.h"
|
#import "GBViewGL.h"
|
||||||
|
#import "GBViewMetal.h"
|
||||||
#import "GBButtons.h"
|
#import "GBButtons.h"
|
||||||
#import "NSString+StringForKey.h"
|
#import "NSString+StringForKey.h"
|
||||||
|
|
||||||
@ -19,16 +20,13 @@
|
|||||||
|
|
||||||
+ (instancetype)alloc
|
+ (instancetype)alloc
|
||||||
{
|
{
|
||||||
if (self == [GBView class]) {
|
return [self allocWithZone:NULL];
|
||||||
return [GBViewGL alloc];
|
|
||||||
}
|
|
||||||
return [super alloc];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (instancetype)allocWithZone:(struct _NSZone *)zone
|
+ (instancetype)allocWithZone:(struct _NSZone *)zone
|
||||||
{
|
{
|
||||||
if (self == [GBView class]) {
|
if (self == [GBView class]) {
|
||||||
return [GBViewGL allocWithZone: zone];
|
return [GBViewMetal allocWithZone: zone];
|
||||||
}
|
}
|
||||||
return [super allocWithZone:zone];
|
return [super allocWithZone:zone];
|
||||||
}
|
}
|
||||||
|
7
Cocoa/GBViewMetal.h
Normal file
7
Cocoa/GBViewMetal.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <MetalKit/MetalKit.h>
|
||||||
|
#import "GBView.h"
|
||||||
|
|
||||||
|
@interface GBViewMetal : GBView<MTKViewDelegate>
|
||||||
|
|
||||||
|
@end
|
131
Cocoa/GBViewMetal.m
Normal file
131
Cocoa/GBViewMetal.m
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
#import "GBViewMetal.h"
|
||||||
|
|
||||||
|
#define WIDTH 160
|
||||||
|
#define HEIGHT 144
|
||||||
|
#define PITCH (160 * 4)
|
||||||
|
|
||||||
|
static const MTLRegion region = {
|
||||||
|
{0, 0, 0}, // MTLOrigin
|
||||||
|
{WIDTH, HEIGHT, 1} // MTLSize
|
||||||
|
};
|
||||||
|
|
||||||
|
static const vector_float2 rect[] =
|
||||||
|
{
|
||||||
|
{-1, -1},
|
||||||
|
{ 1, -1},
|
||||||
|
{-1, 1},
|
||||||
|
{ 1, 1},
|
||||||
|
};
|
||||||
|
|
||||||
|
@implementation GBViewMetal
|
||||||
|
{
|
||||||
|
id<MTLDevice> device;
|
||||||
|
id<MTLTexture> texture, previous_texture;
|
||||||
|
id<MTLBuffer> vertices;
|
||||||
|
id<MTLRenderPipelineState> pipeline_state;
|
||||||
|
id<MTLCommandQueue> command_queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)createInternalView
|
||||||
|
{
|
||||||
|
MTKView *view = [[MTKView alloc] initWithFrame:self.frame device:(device = MTLCreateSystemDefaultDevice())];
|
||||||
|
view.delegate = self;
|
||||||
|
self.internalView = view;
|
||||||
|
|
||||||
|
MTLTextureDescriptor *texture_descriptor = [[MTLTextureDescriptor alloc] init];
|
||||||
|
|
||||||
|
texture_descriptor.pixelFormat = MTLPixelFormatRGBA8Unorm;
|
||||||
|
|
||||||
|
texture_descriptor.width = WIDTH;
|
||||||
|
texture_descriptor.height = HEIGHT;
|
||||||
|
|
||||||
|
texture = [device newTextureWithDescriptor:texture_descriptor];
|
||||||
|
previous_texture = [device newTextureWithDescriptor:texture_descriptor];
|
||||||
|
|
||||||
|
vertices = [device newBufferWithBytes:rect
|
||||||
|
length:sizeof(rect)
|
||||||
|
options:MTLResourceStorageModeShared];
|
||||||
|
|
||||||
|
[self loadShader];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) loadShader
|
||||||
|
{
|
||||||
|
NSError *error = nil;
|
||||||
|
NSString *shader_source = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"MasterShader"
|
||||||
|
ofType:@"metal"
|
||||||
|
inDirectory:@"Shaders"]
|
||||||
|
encoding:NSUTF8StringEncoding
|
||||||
|
error:nil];
|
||||||
|
id<MTLLibrary> library = [device newLibraryWithSource:shader_source
|
||||||
|
options:nil
|
||||||
|
error:&error];
|
||||||
|
if (error) {
|
||||||
|
NSLog(@"Error: %@", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
id<MTLFunction> vertex_function = [library newFunctionWithName:@"vertex_shader"];
|
||||||
|
id<MTLFunction> fragment_function = [library newFunctionWithName:@"fragment_shader"];
|
||||||
|
|
||||||
|
// Set up a descriptor for creating a pipeline state object
|
||||||
|
MTLRenderPipelineDescriptor *pipeline_state_descriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||||
|
pipeline_state_descriptor.vertexFunction = vertex_function;
|
||||||
|
pipeline_state_descriptor.fragmentFunction = fragment_function;
|
||||||
|
pipeline_state_descriptor.colorAttachments[0].pixelFormat = ((MTKView *)self.internalView).colorPixelFormat;
|
||||||
|
|
||||||
|
error = nil;
|
||||||
|
pipeline_state = [device newRenderPipelineStateWithDescriptor:pipeline_state_descriptor
|
||||||
|
error:&error];
|
||||||
|
if (error) {
|
||||||
|
NSLog(@"Failed to created pipeline state, error %@", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
command_queue = [device newCommandQueue];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawInMTKView:(nonnull MTKView *)view
|
||||||
|
{
|
||||||
|
[texture replaceRegion:region
|
||||||
|
mipmapLevel:0
|
||||||
|
withBytes:[self currentBuffer]
|
||||||
|
bytesPerRow:PITCH];
|
||||||
|
|
||||||
|
MTLRenderPassDescriptor *render_pass_descriptor = view.currentRenderPassDescriptor;
|
||||||
|
id<MTLCommandBuffer> command_buffer = [command_queue commandBuffer];
|
||||||
|
|
||||||
|
if(render_pass_descriptor != nil)
|
||||||
|
{
|
||||||
|
id<MTLRenderCommandEncoder> render_encoder =
|
||||||
|
[command_buffer renderCommandEncoderWithDescriptor:render_pass_descriptor];
|
||||||
|
|
||||||
|
[render_encoder setViewport:(MTLViewport){0.0, 0.0,
|
||||||
|
view.bounds.size.width * view.window.backingScaleFactor,
|
||||||
|
view.bounds.size.height * view.window.backingScaleFactor,
|
||||||
|
-1.0, 1.0}];
|
||||||
|
|
||||||
|
[render_encoder setRenderPipelineState:pipeline_state];
|
||||||
|
|
||||||
|
[render_encoder setVertexBuffer:vertices
|
||||||
|
offset:0
|
||||||
|
atIndex:0];
|
||||||
|
|
||||||
|
[render_encoder setFragmentTexture:texture
|
||||||
|
atIndex:0];
|
||||||
|
|
||||||
|
[render_encoder drawPrimitives:MTLPrimitiveTypeTriangleStrip
|
||||||
|
vertexStart:0
|
||||||
|
vertexCount:4];
|
||||||
|
|
||||||
|
[render_encoder endEncoding];
|
||||||
|
|
||||||
|
[command_buffer presentDrawable:view.currentDrawable];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[command_buffer commit];
|
||||||
|
}
|
||||||
|
@end
|
8
Makefile
8
Makefile
@ -61,7 +61,7 @@ ifeq ($(PLATFORM),Darwin)
|
|||||||
SYSROOT := $(shell xcodebuild -sdk macosx -version Path 2> /dev/null)
|
SYSROOT := $(shell xcodebuild -sdk macosx -version Path 2> /dev/null)
|
||||||
CFLAGS += -F/Library/Frameworks
|
CFLAGS += -F/Library/Frameworks
|
||||||
OCFLAGS += -x objective-c -fobjc-arc -Wno-deprecated-declarations -isysroot $(SYSROOT) -mmacosx-version-min=10.9
|
OCFLAGS += -x objective-c -fobjc-arc -Wno-deprecated-declarations -isysroot $(SYSROOT) -mmacosx-version-min=10.9
|
||||||
LDFLAGS += -framework AppKit -framework PreferencePanes -framework Carbon -framework QuartzCore
|
LDFLAGS += -framework AppKit -framework PreferencePanes -framework Carbon -framework QuartzCore -framework Metal -framework MetalKit
|
||||||
SDL_LDFLAGS := -F/Library/Frameworks -framework SDL2 -framework OpenGL
|
SDL_LDFLAGS := -F/Library/Frameworks -framework SDL2 -framework OpenGL
|
||||||
endif
|
endif
|
||||||
CFLAGS += -Wno-deprecated-declarations
|
CFLAGS += -Wno-deprecated-declarations
|
||||||
@ -160,8 +160,6 @@ $(OBJ)/%.m.o: %.m
|
|||||||
|
|
||||||
# Cocoa Port
|
# Cocoa Port
|
||||||
|
|
||||||
Shaders:$(shell ls Shaders/*.fsh)
|
|
||||||
|
|
||||||
$(BIN)/SameBoy.app: $(BIN)/SameBoy.app/Contents/MacOS/SameBoy \
|
$(BIN)/SameBoy.app: $(BIN)/SameBoy.app/Contents/MacOS/SameBoy \
|
||||||
$(shell ls Cocoa/*.icns) \
|
$(shell ls Cocoa/*.icns) \
|
||||||
Cocoa/License.html \
|
Cocoa/License.html \
|
||||||
@ -178,7 +176,7 @@ $(BIN)/SameBoy.app: $(BIN)/SameBoy.app/Contents/MacOS/SameBoy \
|
|||||||
sed s/@VERSION/$(VERSION)/ < Cocoa/Info.plist > $(BIN)/SameBoy.app/Contents/Info.plist
|
sed s/@VERSION/$(VERSION)/ < Cocoa/Info.plist > $(BIN)/SameBoy.app/Contents/Info.plist
|
||||||
cp Cocoa/License.html $(BIN)/SameBoy.app/Contents/Resources/Credits.html
|
cp Cocoa/License.html $(BIN)/SameBoy.app/Contents/Resources/Credits.html
|
||||||
$(MKDIR) -p $(BIN)/SameBoy.app/Contents/Resources/Shaders
|
$(MKDIR) -p $(BIN)/SameBoy.app/Contents/Resources/Shaders
|
||||||
cp Shaders/*.fsh $(BIN)/SameBoy.app/Contents/Resources/Shaders
|
cp Shaders/*.fsh Shaders/*.metal $(BIN)/SameBoy.app/Contents/Resources/Shaders
|
||||||
$(MKDIR) -p $(BIN)/SameBoy.app/Contents/Library/QuickLook/
|
$(MKDIR) -p $(BIN)/SameBoy.app/Contents/Library/QuickLook/
|
||||||
cp -rf $(BIN)/SameBoy.qlgenerator $(BIN)/SameBoy.app/Contents/Library/QuickLook/
|
cp -rf $(BIN)/SameBoy.qlgenerator $(BIN)/SameBoy.app/Contents/Library/QuickLook/
|
||||||
|
|
||||||
@ -289,7 +287,7 @@ $(BIN)/SDL/background.bmp: SDL/background.bmp
|
|||||||
|
|
||||||
$(BIN)/SDL/Shaders: Shaders
|
$(BIN)/SDL/Shaders: Shaders
|
||||||
-@$(MKDIR) -p $(dir $@)
|
-@$(MKDIR) -p $(dir $@)
|
||||||
cp -rf $^ $@
|
cp -rf Shaders/*.fsh $@
|
||||||
|
|
||||||
# Boot ROMs
|
# Boot ROMs
|
||||||
|
|
||||||
|
45
Shaders/MasterShader.metal
Normal file
45
Shaders/MasterShader.metal
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
#include <metal_math>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
/* For GLSL compatibility */
|
||||||
|
typedef float2 vec2;
|
||||||
|
typedef float3 vec3;
|
||||||
|
typedef float4 vec4;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float4 position [[position]];
|
||||||
|
float2 texcoords;
|
||||||
|
} rasterizer_data;
|
||||||
|
|
||||||
|
// Vertex Function
|
||||||
|
vertex rasterizer_data vertex_shader(uint index [[ vertex_id ]],
|
||||||
|
constant vector_float2 *vertices [[ buffer(0) ]])
|
||||||
|
|
||||||
|
{
|
||||||
|
rasterizer_data out;
|
||||||
|
|
||||||
|
out.position.xy = vertices[index].xy;
|
||||||
|
out.position.z = 0.0;
|
||||||
|
out.position.w = 1.0;
|
||||||
|
out.texcoords = (vertices[index].xy + float2(1, 1)) / 2.0;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline float4 texture(texture2d<half> texture, float2 pos)
|
||||||
|
{
|
||||||
|
constexpr sampler texture_sampler;
|
||||||
|
return float4(texture.sample(texture_sampler, pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 fragment_shader(rasterizer_data in [[stage_in]],
|
||||||
|
texture2d<half> image [[ texture(0) ]])
|
||||||
|
{
|
||||||
|
in.texcoords.y = 1 - in.texcoords.y;
|
||||||
|
return texture(image, in.texcoords);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user