unify a little bit more iOS & MacOS
This commit is contained in:
parent
75de20e4cc
commit
80a7a33b7c
@ -11,7 +11,7 @@
|
|||||||
SWindowData *
|
SWindowData *
|
||||||
create_window_data(unsigned width, unsigned height) {
|
create_window_data(unsigned width, unsigned height) {
|
||||||
SWindowData *window_data;
|
SWindowData *window_data;
|
||||||
|
|
||||||
window_data = malloc(sizeof(SWindowData));
|
window_data = malloc(sizeof(SWindowData));
|
||||||
if(window_data == 0x0) {
|
if(window_data == 0x0) {
|
||||||
NSLog(@"Cannot allocate window data");
|
NSLog(@"Cannot allocate window data");
|
||||||
@ -48,7 +48,7 @@ create_window_data(unsigned width, unsigned height) {
|
|||||||
NSLog(@"Unable to create draw buffer");
|
NSLog(@"Unable to create draw buffer");
|
||||||
return 0x0;
|
return 0x0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return window_data;
|
return window_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,20 +67,11 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags)
|
|||||||
|
|
||||||
kUnused(title);
|
kUnused(title);
|
||||||
kUnused(flags);
|
kUnused(flags);
|
||||||
|
|
||||||
SWindowData *window_data = create_window_data(width, height);
|
SWindowData *window_data = create_window_data(width, height);
|
||||||
if (window_data == 0x0) {
|
if (window_data == 0x0) {
|
||||||
return 0x0;
|
return 0x0;
|
||||||
}
|
}
|
||||||
SWindowData_IOS *window_data_ios = (SWindowData_IOS *) window_data->specific;
|
|
||||||
|
|
||||||
static Vertex s_vertices[4] = {
|
|
||||||
{-1.0, -1.0, 0, 1},
|
|
||||||
{-1.0, 1.0, 0, 1},
|
|
||||||
{ 1.0, -1.0, 0, 1},
|
|
||||||
{ 1.0, 1.0, 0, 1},
|
|
||||||
};
|
|
||||||
memcpy(window_data_ios->vertices, s_vertices, sizeof(s_vertices));
|
|
||||||
|
|
||||||
windows = [[UIApplication sharedApplication] windows];
|
windows = [[UIApplication sharedApplication] windows];
|
||||||
numWindows = [windows count];
|
numWindows = [windows count];
|
||||||
@ -94,7 +85,7 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags)
|
|||||||
window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||||
NSLog(@"UIApplication has no window. We create one (%f, %f).", [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
|
NSLog(@"UIApplication has no window. We create one (%f, %f).", [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
if([window.rootViewController isKindOfClass:[iOSViewController class]] == false) {
|
if([window.rootViewController isKindOfClass:[iOSViewController class]] == false) {
|
||||||
iOSViewController *controller = [[iOSViewController alloc] initWithWindowData:window_data];
|
iOSViewController *controller = [[iOSViewController alloc] initWithWindowData:window_data];
|
||||||
[window setRootViewController:controller];
|
[window setRootViewController:controller];
|
||||||
@ -216,7 +207,7 @@ mfb_timer_tick() {
|
|||||||
if (timebase.denom == 0) {
|
if (timebase.denom == 0) {
|
||||||
(void) mach_timebase_info(&timebase);
|
(void) mach_timebase_info(&timebase);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t time = mach_absolute_time();
|
uint64_t time = mach_absolute_time();
|
||||||
|
|
||||||
//return (time * s_timebase_info.numer) / s_timebase_info.denom;
|
//return (time * s_timebase_info.numer) / s_timebase_info.denom;
|
||||||
@ -226,7 +217,7 @@ mfb_timer_tick() {
|
|||||||
uint64_t highRem = ((high % timebase.denom) << 32) / timebase.denom;
|
uint64_t highRem = ((high % timebase.denom) << 32) / timebase.denom;
|
||||||
uint64_t low = (time & 0xFFFFFFFFull) * timebase.numer / timebase.denom;
|
uint64_t low = (time & 0xFFFFFFFFull) * timebase.numer / timebase.denom;
|
||||||
high /= timebase.denom;
|
high /= timebase.denom;
|
||||||
|
|
||||||
return (high << 32) + highRem + low;
|
return (high << 32) + highRem + low;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,15 +8,12 @@
|
|||||||
|
|
||||||
#import <MetalKit/MetalKit.h>
|
#import <MetalKit/MetalKit.h>
|
||||||
#include "WindowData.h"
|
#include "WindowData.h"
|
||||||
#include "WindowData_IOS.h"
|
|
||||||
|
|
||||||
// Our platform independent renderer class.
|
// Our platform independent renderer class.
|
||||||
// Implements the MTKViewDelegate protocol which allows it to accept per-frame
|
// Implements the MTKViewDelegate protocol which allows it to accept per-frame
|
||||||
// update and drawable resize callbacks.
|
// update and drawable resize callbacks.
|
||||||
@interface iOSViewDelegate : NSObject <MTKViewDelegate>
|
@interface iOSViewDelegate : NSObject <MTKViewDelegate>
|
||||||
{
|
{
|
||||||
@public SWindowData *window_data;
|
|
||||||
@public SWindowData_IOS *window_data_ios;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-(nonnull instancetype) initWithMetalKitView:(nonnull MTKView *) view windowData:(nonnull SWindowData *) windowData;
|
-(nonnull instancetype) initWithMetalKitView:(nonnull MTKView *) view windowData:(nonnull SWindowData *) windowData;
|
||||||
|
@ -21,25 +21,23 @@
|
|||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
enum { MaxBuffersInFlight = 3 }; // Number of textures in flight (tripple buffered)
|
enum { MaxBuffersInFlight = 3 }; // Number of textures in flight (tripple buffered)
|
||||||
|
|
||||||
id<MTLDevice> g_metal_device = nil;
|
|
||||||
id<MTLLibrary> g_library = nil;
|
|
||||||
|
|
||||||
//--
|
//--
|
||||||
NSString *g_shader_src = kShader(
|
NSString *g_shader_src = kShader(
|
||||||
"#include <metal_stdlib>\n",
|
"#include <metal_stdlib>\n",
|
||||||
using namespace metal;
|
using namespace metal;
|
||||||
|
|
||||||
//---------------------
|
//-------------
|
||||||
struct VertexOutput {
|
struct VertexOutput {
|
||||||
float4 pos [[position]];
|
float4 pos [[position]];
|
||||||
float2 texcoord;
|
float2 texcoord;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//-------------
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
float4 position [[position]];
|
float4 position [[position]];
|
||||||
};
|
};
|
||||||
|
|
||||||
//---------------------
|
//-------------
|
||||||
vertex VertexOutput
|
vertex VertexOutput
|
||||||
vertFunc(unsigned int vID[[vertex_id]], const device Vertex *pos [[ buffer(0) ]]) {
|
vertFunc(unsigned int vID[[vertex_id]], const device Vertex *pos [[ buffer(0) ]]) {
|
||||||
VertexOutput out;
|
VertexOutput out;
|
||||||
@ -52,7 +50,7 @@ NSString *g_shader_src = kShader(
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------
|
//-------------
|
||||||
fragment float4
|
fragment float4
|
||||||
fragFunc(VertexOutput input [[stage_in]], texture2d<half> colorTexture [[ texture(0) ]]) {
|
fragFunc(VertexOutput input [[stage_in]], texture2d<half> colorTexture [[ texture(0) ]]) {
|
||||||
constexpr sampler textureSampler(mag_filter::nearest, min_filter::nearest);
|
constexpr sampler textureSampler(mag_filter::nearest, min_filter::nearest);
|
||||||
@ -67,29 +65,38 @@ NSString *g_shader_src = kShader(
|
|||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
@implementation iOSViewDelegate {
|
@implementation iOSViewDelegate {
|
||||||
dispatch_semaphore_t m_semaphore;
|
SWindowData *window_data;
|
||||||
id <MTLCommandQueue> m_command_queue;
|
SWindowData_IOS *window_data_ios;
|
||||||
|
|
||||||
|
id<MTLDevice> metal_device;
|
||||||
|
id<MTLLibrary> metal_library;
|
||||||
|
|
||||||
id <MTLRenderPipelineState> m_pipeline_state;
|
dispatch_semaphore_t semaphore;
|
||||||
id <MTLTexture> m_texture_buffer;
|
id<MTLCommandQueue> command_queue;
|
||||||
|
|
||||||
uint8_t m_current_buffer;
|
id<MTLRenderPipelineState> pipeline_state;
|
||||||
|
id<MTLTexture> texture_buffer;
|
||||||
|
|
||||||
|
uint8_t current_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
-(nonnull instancetype) initWithMetalKitView:(nonnull MTKView *) view windowData:(nonnull SWindowData *) windowData {
|
-(nonnull instancetype) initWithMetalKitView:(nonnull MTKView *) view windowData:(nonnull SWindowData *) windowData {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
self->window_data = windowData;
|
window_data = windowData;
|
||||||
self->window_data_ios = (SWindowData_IOS *) windowData->specific;
|
window_data_ios = (SWindowData_IOS *) windowData->specific;
|
||||||
|
|
||||||
view.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
|
view.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||||
view.sampleCount = 1;
|
view.sampleCount = 1;
|
||||||
|
|
||||||
g_metal_device = view.device;
|
metal_device = view.device;
|
||||||
|
|
||||||
m_semaphore = dispatch_semaphore_create(MaxBuffersInFlight);
|
// Used for syncing the CPU and GPU
|
||||||
m_command_queue = [g_metal_device newCommandQueue];
|
semaphore = dispatch_semaphore_create(MaxBuffersInFlight);
|
||||||
|
|
||||||
|
// Setup command queue
|
||||||
|
command_queue = [metal_device newCommandQueue];
|
||||||
|
|
||||||
[self _createShaders];
|
[self _createShaders];
|
||||||
[self _createAssets];
|
[self _createAssets];
|
||||||
@ -100,19 +107,19 @@ NSString *g_shader_src = kShader(
|
|||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
- (bool) _createShaders {
|
- (bool) _createShaders {
|
||||||
NSError *error = nil;
|
NSError *error = 0x0;
|
||||||
|
|
||||||
g_library = [g_metal_device newLibraryWithSource:g_shader_src
|
metal_library = [metal_device newLibraryWithSource:g_shader_src
|
||||||
options:[[MTLCompileOptions alloc] init]
|
options:[[MTLCompileOptions alloc] init]
|
||||||
error:&error
|
error:&error
|
||||||
];
|
];
|
||||||
if (error || !g_library) {
|
if (error || !metal_library) {
|
||||||
NSLog(@"Unable to create shaders %@", error);
|
NSLog(@"Unable to create shaders %@", error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
id<MTLFunction> vertex_shader_func = [g_library newFunctionWithName:@"vertFunc"];
|
id<MTLFunction> vertex_shader_func = [metal_library newFunctionWithName:@"vertFunc"];
|
||||||
id<MTLFunction> fragment_shader_func = [g_library newFunctionWithName:@"fragFunc"];
|
id<MTLFunction> fragment_shader_func = [metal_library newFunctionWithName:@"fragFunc"];
|
||||||
|
|
||||||
if (!vertex_shader_func) {
|
if (!vertex_shader_func) {
|
||||||
NSLog(@"Unable to get vertFunc!\n");
|
NSLog(@"Unable to get vertFunc!\n");
|
||||||
@ -124,14 +131,15 @@ NSString *g_shader_src = kShader(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a reusable pipeline state
|
||||||
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||||
pipelineStateDescriptor.label = @"MiniFB_pipeline";
|
pipelineStateDescriptor.label = @"MiniFB_pipeline";
|
||||||
pipelineStateDescriptor.vertexFunction = vertex_shader_func;
|
pipelineStateDescriptor.vertexFunction = vertex_shader_func;
|
||||||
pipelineStateDescriptor.fragmentFunction = fragment_shader_func;
|
pipelineStateDescriptor.fragmentFunction = fragment_shader_func;
|
||||||
pipelineStateDescriptor.colorAttachments[0].pixelFormat = 80; //bgra8Unorm;
|
pipelineStateDescriptor.colorAttachments[0].pixelFormat = 80; //bgra8Unorm;
|
||||||
|
|
||||||
m_pipeline_state = [g_metal_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error];
|
pipeline_state = [metal_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error];
|
||||||
if (!m_pipeline_state) {
|
if (!pipeline_state) {
|
||||||
NSLog(@"Failed to created pipeline state, error %@", error);
|
NSLog(@"Failed to created pipeline state, error %@", error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -141,26 +149,42 @@ NSString *g_shader_src = kShader(
|
|||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
- (void) _createAssets {
|
- (void) _createAssets {
|
||||||
|
static Vertex s_vertices[4] = {
|
||||||
|
{-1.0, -1.0, 0, 1},
|
||||||
|
{-1.0, 1.0, 0, 1},
|
||||||
|
{ 1.0, -1.0, 0, 1},
|
||||||
|
{ 1.0, 1.0, 0, 1},
|
||||||
|
};
|
||||||
|
memcpy(window_data_ios->vertices, s_vertices, sizeof(s_vertices));
|
||||||
|
|
||||||
MTLTextureDescriptor *td;
|
MTLTextureDescriptor *td;
|
||||||
td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
|
td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
|
||||||
width:window_data->buffer_width
|
width:window_data->buffer_width
|
||||||
height:window_data->buffer_height
|
height:window_data->buffer_height
|
||||||
mipmapped:false];
|
mipmapped:false];
|
||||||
|
|
||||||
m_texture_buffer = [g_metal_device newTextureWithDescriptor:td];
|
// Create the texture from the device by using the descriptor
|
||||||
|
texture_buffer = [metal_device newTextureWithDescriptor:td];
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
- (void) drawInMTKView:(nonnull MTKView *) view {
|
- (void) drawInMTKView:(nonnull MTKView *) view {
|
||||||
// Per frame updates here
|
// Wait to ensure only MaxBuffersInFlight number of frames are getting proccessed
|
||||||
dispatch_semaphore_wait(m_semaphore, DISPATCH_TIME_FOREVER);
|
// by any stage in the Metal pipeline (App, Metal, Drivers, GPU, etc)
|
||||||
|
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||||
|
|
||||||
m_current_buffer = (m_current_buffer + 1) % MaxBuffersInFlight;
|
current_buffer = (current_buffer + 1) % MaxBuffersInFlight;
|
||||||
|
|
||||||
id <MTLCommandBuffer> commandBuffer = [m_command_queue commandBuffer];
|
// Create a new command buffer for each render pass to the current drawable
|
||||||
|
id<MTLCommandBuffer> commandBuffer = [command_queue commandBuffer];
|
||||||
commandBuffer.label = @"minifb_command_buffer";
|
commandBuffer.label = @"minifb_command_buffer";
|
||||||
|
|
||||||
__block dispatch_semaphore_t block_sema = m_semaphore;
|
// Add completion hander which signals semaphore when Metal and the GPU has fully
|
||||||
|
// finished processing the commands we're encoding this frame. This indicates when the
|
||||||
|
// dynamic buffers filled with our vertices, that we're writing to this frame, will no longer
|
||||||
|
// be needed by Metal and the GPU, meaning we can overwrite the buffer contents without
|
||||||
|
// corrupting the rendering.
|
||||||
|
__block dispatch_semaphore_t block_sema = semaphore;
|
||||||
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
|
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
|
||||||
(void)buffer;
|
(void)buffer;
|
||||||
dispatch_semaphore_signal(block_sema);
|
dispatch_semaphore_signal(block_sema);
|
||||||
@ -168,7 +192,7 @@ NSString *g_shader_src = kShader(
|
|||||||
|
|
||||||
// Copy the bytes from our data object into the texture
|
// Copy the bytes from our data object into the texture
|
||||||
MTLRegion region = { { 0, 0, 0 }, { window_data->buffer_width, window_data->buffer_height, 1 } };
|
MTLRegion region = { { 0, 0, 0 }, { window_data->buffer_width, window_data->buffer_height, 1 } };
|
||||||
[m_texture_buffer replaceRegion:region mipmapLevel:0 withBytes:window_data->draw_buffer bytesPerRow:window_data->buffer_stride];
|
[texture_buffer replaceRegion:region mipmapLevel:0 withBytes:window_data->draw_buffer bytesPerRow:window_data->buffer_stride];
|
||||||
|
|
||||||
// Delay getting the currentRenderPassDescriptor until absolutely needed. This avoids
|
// Delay getting the currentRenderPassDescriptor until absolutely needed. This avoids
|
||||||
// holding onto the drawable and blocking the display pipeline any longer than necessary
|
// holding onto the drawable and blocking the display pipeline any longer than necessary
|
||||||
@ -181,11 +205,11 @@ NSString *g_shader_src = kShader(
|
|||||||
renderEncoder.label = @"minifb_command_encoder";
|
renderEncoder.label = @"minifb_command_encoder";
|
||||||
|
|
||||||
// Set render command encoder state
|
// Set render command encoder state
|
||||||
[renderEncoder setRenderPipelineState:m_pipeline_state];
|
[renderEncoder setRenderPipelineState:pipeline_state];
|
||||||
[renderEncoder setVertexBytes:window_data_ios->vertices length:sizeof(window_data_ios->vertices) atIndex:0];
|
[renderEncoder setVertexBytes:window_data_ios->vertices length:sizeof(window_data_ios->vertices) atIndex:0];
|
||||||
|
|
||||||
//[renderEncoder setFragmentTexture:m_texture_buffers[m_current_buffer] atIndex:0];
|
//[renderEncoder setFragmentTexture:texture_buffers[current_buffer] atIndex:0];
|
||||||
[renderEncoder setFragmentTexture:m_texture_buffer atIndex:0];
|
[renderEncoder setFragmentTexture:texture_buffer atIndex:0];
|
||||||
|
|
||||||
// Draw the vertices of our quads
|
// Draw the vertices of our quads
|
||||||
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
||||||
|
@ -132,7 +132,7 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags)
|
|||||||
OSXViewController *viewController = [[OSXViewController alloc] initWithWindowData:window_data];
|
OSXViewController *viewController = [[OSXViewController alloc] initWithWindowData:window_data];
|
||||||
|
|
||||||
MTKView* view = [[MTKView alloc] initWithFrame:rectangle];
|
MTKView* view = [[MTKView alloc] initWithFrame:rectangle];
|
||||||
view.device = viewController->metal_device;
|
view.device = viewController->metal_device;
|
||||||
view.delegate = viewController;
|
view.delegate = viewController;
|
||||||
view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
|
view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
|
||||||
[window_data_osx->window.contentView addSubview:view];
|
[window_data_osx->window.contentView addSubview:view];
|
||||||
@ -169,13 +169,13 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags)
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static void
|
static void
|
||||||
destroy_window_data(SWindowData *window_data) {
|
destroy_window_data(SWindowData *window_data) {
|
||||||
if(window_data == 0x0)
|
if(window_data == 0x0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific;
|
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific;
|
||||||
if(window_data_osx != 0x0) {
|
if(window_data_osx != 0x0) {
|
||||||
OSXWindow *window = window_data_osx->window;
|
OSXWindow *window = window_data_osx->window;
|
||||||
@ -201,7 +201,7 @@ destroy_window_data(SWindowData *window_data) {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static void
|
static void
|
||||||
update_events(SWindowData *window_data) {
|
update_events(SWindowData *window_data) {
|
||||||
NSEvent* event;
|
NSEvent* event;
|
||||||
|
|
||||||
@ -218,7 +218,7 @@ update_events(SWindowData *window_data) {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
mfb_update_state
|
mfb_update_state
|
||||||
mfb_update(struct mfb_window *window, void *buffer) {
|
mfb_update(struct mfb_window *window, void *buffer) {
|
||||||
if(window == 0x0) {
|
if(window == 0x0) {
|
||||||
return STATE_INVALID_WINDOW;
|
return STATE_INVALID_WINDOW;
|
||||||
@ -254,7 +254,7 @@ mfb_update(struct mfb_window *window, void *buffer) {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
mfb_update_state
|
mfb_update_state
|
||||||
mfb_update_events(struct mfb_window *window) {
|
mfb_update_events(struct mfb_window *window) {
|
||||||
if(window == 0x0) {
|
if(window == 0x0) {
|
||||||
return STATE_INVALID_WINDOW;
|
return STATE_INVALID_WINDOW;
|
||||||
@ -310,7 +310,7 @@ mfb_wait_sync(struct mfb_window *window) {
|
|||||||
if (event) {
|
if (event) {
|
||||||
[NSApp sendEvent:event];
|
[NSApp sendEvent:event];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(window_data->close) {
|
if(window_data->close) {
|
||||||
destroy_window_data(window_data);
|
destroy_window_data(window_data);
|
||||||
return false;
|
return false;
|
||||||
@ -324,7 +324,7 @@ mfb_wait_sync(struct mfb_window *window) {
|
|||||||
else if(current >= g_time_for_frame * 0.8) {
|
else if(current >= g_time_for_frame * 0.8) {
|
||||||
millis = 0;
|
millis = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
usleep(millis * 1000);
|
usleep(millis * 1000);
|
||||||
//sched_yield();
|
//sched_yield();
|
||||||
}
|
}
|
||||||
@ -336,7 +336,7 @@ mfb_wait_sync(struct mfb_window *window) {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool
|
bool
|
||||||
mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) {
|
mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) {
|
||||||
if(window == 0x0) {
|
if(window == 0x0) {
|
||||||
return false;
|
return false;
|
||||||
@ -384,10 +384,10 @@ mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y
|
|||||||
|
|
||||||
extern short int g_keycodes[512];
|
extern short int g_keycodes[512];
|
||||||
|
|
||||||
void
|
void
|
||||||
init_keycodes() {
|
init_keycodes() {
|
||||||
// Clear keys
|
// Clear keys
|
||||||
for (unsigned int i = 0; i < sizeof(g_keycodes) / sizeof(g_keycodes[0]); ++i)
|
for (unsigned int i = 0; i < sizeof(g_keycodes) / sizeof(g_keycodes[0]); ++i)
|
||||||
g_keycodes[i] = 0;
|
g_keycodes[i] = 0;
|
||||||
|
|
||||||
g_keycodes[0x1D] = KB_KEY_0;
|
g_keycodes[0x1D] = KB_KEY_0;
|
||||||
@ -426,7 +426,7 @@ init_keycodes() {
|
|||||||
g_keycodes[0x07] = KB_KEY_X;
|
g_keycodes[0x07] = KB_KEY_X;
|
||||||
g_keycodes[0x10] = KB_KEY_Y;
|
g_keycodes[0x10] = KB_KEY_Y;
|
||||||
g_keycodes[0x06] = KB_KEY_Z;
|
g_keycodes[0x06] = KB_KEY_Z;
|
||||||
|
|
||||||
g_keycodes[0x27] = KB_KEY_APOSTROPHE;
|
g_keycodes[0x27] = KB_KEY_APOSTROPHE;
|
||||||
g_keycodes[0x2A] = KB_KEY_BACKSLASH;
|
g_keycodes[0x2A] = KB_KEY_BACKSLASH;
|
||||||
g_keycodes[0x2B] = KB_KEY_COMMA;
|
g_keycodes[0x2B] = KB_KEY_COMMA;
|
||||||
@ -439,7 +439,7 @@ init_keycodes() {
|
|||||||
g_keycodes[0x29] = KB_KEY_SEMICOLON;
|
g_keycodes[0x29] = KB_KEY_SEMICOLON;
|
||||||
g_keycodes[0x2C] = KB_KEY_SLASH;
|
g_keycodes[0x2C] = KB_KEY_SLASH;
|
||||||
g_keycodes[0x0A] = KB_KEY_WORLD_1;
|
g_keycodes[0x0A] = KB_KEY_WORLD_1;
|
||||||
|
|
||||||
g_keycodes[0x33] = KB_KEY_BACKSPACE;
|
g_keycodes[0x33] = KB_KEY_BACKSPACE;
|
||||||
g_keycodes[0x39] = KB_KEY_CAPS_LOCK;
|
g_keycodes[0x39] = KB_KEY_CAPS_LOCK;
|
||||||
g_keycodes[0x75] = KB_KEY_DELETE;
|
g_keycodes[0x75] = KB_KEY_DELETE;
|
||||||
@ -486,7 +486,7 @@ init_keycodes() {
|
|||||||
g_keycodes[0x31] = KB_KEY_SPACE;
|
g_keycodes[0x31] = KB_KEY_SPACE;
|
||||||
g_keycodes[0x30] = KB_KEY_TAB;
|
g_keycodes[0x30] = KB_KEY_TAB;
|
||||||
g_keycodes[0x7E] = KB_KEY_UP;
|
g_keycodes[0x7E] = KB_KEY_UP;
|
||||||
|
|
||||||
g_keycodes[0x52] = KB_KEY_KP_0;
|
g_keycodes[0x52] = KB_KEY_KP_0;
|
||||||
g_keycodes[0x53] = KB_KEY_KP_1;
|
g_keycodes[0x53] = KB_KEY_KP_1;
|
||||||
g_keycodes[0x54] = KB_KEY_KP_2;
|
g_keycodes[0x54] = KB_KEY_KP_2;
|
||||||
@ -511,14 +511,14 @@ init_keycodes() {
|
|||||||
extern double g_timer_frequency;
|
extern double g_timer_frequency;
|
||||||
extern double g_timer_resolution;
|
extern double g_timer_resolution;
|
||||||
|
|
||||||
uint64_t
|
uint64_t
|
||||||
mfb_timer_tick() {
|
mfb_timer_tick() {
|
||||||
static mach_timebase_info_data_t timebase = { 0 };
|
static mach_timebase_info_data_t timebase = { 0 };
|
||||||
|
|
||||||
if (timebase.denom == 0) {
|
if (timebase.denom == 0) {
|
||||||
(void) mach_timebase_info(&timebase);
|
(void) mach_timebase_info(&timebase);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t time = mach_absolute_time();
|
uint64_t time = mach_absolute_time();
|
||||||
|
|
||||||
//return (time * s_timebase_info.numer) / s_timebase_info.denom;
|
//return (time * s_timebase_info.numer) / s_timebase_info.denom;
|
||||||
@ -528,11 +528,11 @@ mfb_timer_tick() {
|
|||||||
uint64_t highRem = ((high % timebase.denom) << 32) / timebase.denom;
|
uint64_t highRem = ((high % timebase.denom) << 32) / timebase.denom;
|
||||||
uint64_t low = (time & 0xFFFFFFFFull) * timebase.numer / timebase.denom;
|
uint64_t low = (time & 0xFFFFFFFFull) * timebase.numer / timebase.denom;
|
||||||
high /= timebase.denom;
|
high /= timebase.denom;
|
||||||
|
|
||||||
return (high << 32) + highRem + low;
|
return (high << 32) + highRem + low;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mfb_timer_init() {
|
mfb_timer_init() {
|
||||||
g_timer_frequency = 1e+9;
|
g_timer_frequency = 1e+9;
|
||||||
g_timer_resolution = 1.0 / g_timer_frequency;
|
g_timer_resolution = 1.0 / g_timer_frequency;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#import "OSXView.h"
|
#import "OSXView.h"
|
||||||
#import "OSXWindow.h"
|
#import "OSXWindow.h"
|
||||||
|
#import "WindowData_OSX.h"
|
||||||
#include <MiniFB_internal.h>
|
#include <MiniFB_internal.h>
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
@ -22,13 +23,13 @@
|
|||||||
[self addTrackingArea:tracking_area];
|
[self addTrackingArea:tracking_area];
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
- (NSRect)resizeRect {
|
- (NSRect)resizeRect {
|
||||||
const CGFloat resizeBoxSize = 16.0;
|
const CGFloat resizeBoxSize = 16.0;
|
||||||
const CGFloat contentViewPadding = 5.5;
|
const CGFloat contentViewPadding = 5.5;
|
||||||
|
|
||||||
NSRect contentViewRect = [[self window] contentRectForFrameRect:[[self window] frame]];
|
NSRect contentViewRect = [[self window] contentRectForFrameRect:[[self window] frame]];
|
||||||
NSRect resizeRect = NSMakeRect(
|
NSRect resizeRect = NSMakeRect(
|
||||||
NSMaxX(contentViewRect) + contentViewPadding,
|
NSMaxX(contentViewRect) + contentViewPadding,
|
||||||
@ -36,7 +37,7 @@
|
|||||||
resizeBoxSize,
|
resizeBoxSize,
|
||||||
resizeBoxSize
|
resizeBoxSize
|
||||||
);
|
);
|
||||||
|
|
||||||
return resizeRect;
|
return resizeRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,16 +48,16 @@
|
|||||||
if(window_data == 0x0)
|
if(window_data == 0x0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific;
|
SWindowData_OSX *window_data_osx = (SWindowData_OSX *) window_data->specific;
|
||||||
if (!window_data_osx || !window_data_osx->window || !window_data->draw_buffer)
|
if (!window_data_osx || !window_data_osx->window || !window_data->draw_buffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
|
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
|
||||||
|
|
||||||
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
|
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
|
||||||
CGDataProviderRef provider = CGDataProviderCreateWithData(0x0, window_data->draw_buffer, window_data->buffer_width * window_data->buffer_height * 4, 0x0);
|
CGDataProviderRef provider = CGDataProviderCreateWithData(0x0, window_data->draw_buffer, window_data->buffer_width * window_data->buffer_height * 4, 0x0);
|
||||||
|
|
||||||
CGImageRef img = CGImageCreate(window_data->buffer_width, window_data->buffer_height, 8, 32, window_data->buffer_width * 4, space, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little,
|
CGImageRef img = CGImageCreate(window_data->buffer_width, window_data->buffer_height, 8, 32, window_data->buffer_width * 4, space, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little,
|
||||||
provider, 0x0, false, kCGRenderingIntentDefault);
|
provider, 0x0, false, kCGRenderingIntentDefault);
|
||||||
|
|
||||||
const CGFloat components[] = {0.0f, 0.0f, 0.0f, 1.0f};
|
const CGFloat components[] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
@ -69,7 +70,7 @@
|
|||||||
CGContextSetFillColorWithColor(context, black);
|
CGContextSetFillColorWithColor(context, black);
|
||||||
CGContextFillRect(context, CGRectMake(0, 0, window_data->window_width, window_data->window_height));
|
CGContextFillRect(context, CGRectMake(0, 0, window_data->window_width, window_data->window_height));
|
||||||
}
|
}
|
||||||
|
|
||||||
CGContextDrawImage(context, CGRectMake(window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height), img);
|
CGContextDrawImage(context, CGRectMake(window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height), img);
|
||||||
|
|
||||||
CGImageRelease(img);
|
CGImageRelease(img);
|
||||||
|
@ -1,27 +1,34 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if defined(USE_METAL_API)
|
#if defined(USE_METAL_API)
|
||||||
#include "WindowData_OSX.h"
|
|
||||||
#import <MetalKit/MetalKit.h>
|
#import <MetalKit/MetalKit.h>
|
||||||
|
#include "WindowData_OSX.h"
|
||||||
|
|
||||||
// Number of textures in flight (tripple buffered)
|
// Number of textures in flight (tripple buffered)
|
||||||
enum { MaxBuffersInFlight = 3 };
|
enum { MaxBuffersInFlight = 3 };
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@interface OSXViewController : NSViewController<MTKViewDelegate>
|
@interface OSXViewController : NSViewController<MTKViewDelegate>
|
||||||
{
|
{
|
||||||
@public SWindowData *window_data;
|
@public SWindowData *window_data;
|
||||||
@public SWindowData_OSX *window_data_osx;
|
@public SWindowData_OSX *window_data_osx;
|
||||||
|
|
||||||
@public id<MTLDevice> metal_device;
|
id<MTLDevice> metal_device;
|
||||||
@public id<MTLLibrary> metal_library;
|
id<MTLLibrary> metal_library;
|
||||||
@public id<MTLTexture> texture_buffers[MaxBuffersInFlight];
|
|
||||||
@public int current_buffer;
|
dispatch_semaphore_t semaphore; // Used for syncing with CPU/GPU
|
||||||
@public dispatch_semaphore_t semaphore; // Used for syncing with CPU/GPU
|
id<MTLCommandQueue> command_queue;
|
||||||
|
|
||||||
|
id<MTLRenderPipelineState> pipeline_state;
|
||||||
|
id<MTLTexture> texture_buffers[MaxBuffersInFlight];
|
||||||
|
|
||||||
|
int current_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id) initWithWindowData:(SWindowData *) windowData;
|
- (id) initWithWindowData:(SWindowData *) windowData;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "OSXViewController.h"
|
#include "OSXViewController.h"
|
||||||
|
|
||||||
#if defined(USE_METAL_API)
|
#if defined(USE_METAL_API)
|
||||||
|
|
||||||
#import <MetalKit/MetalKit.h>
|
#import <MetalKit/MetalKit.h>
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
@ -63,28 +64,28 @@ NSString *g_shader_src = kShader(
|
|||||||
return 0x0;
|
return 0x0;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self _create_shaders];
|
|
||||||
[self _createAssets];
|
|
||||||
|
|
||||||
// Used for syncing the CPU and GPU
|
// Used for syncing the CPU and GPU
|
||||||
semaphore = dispatch_semaphore_create(MaxBuffersInFlight);
|
semaphore = dispatch_semaphore_create(MaxBuffersInFlight);
|
||||||
|
|
||||||
// Setup command queue
|
// Setup command queue
|
||||||
window_data_osx->metal.command_queue = [metal_device newCommandQueue];
|
command_queue = [metal_device newCommandQueue];
|
||||||
|
|
||||||
|
[self _createShaders];
|
||||||
|
[self _createAssets];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
- (bool) _create_shaders {
|
- (bool) _createShaders {
|
||||||
NSError *error = 0x0;
|
NSError *error = 0x0;
|
||||||
|
|
||||||
metal_library = [metal_device newLibraryWithSource:g_shader_src
|
metal_library = [metal_device newLibraryWithSource:g_shader_src
|
||||||
options:[[MTLCompileOptions alloc] init]
|
options:[[MTLCompileOptions alloc] init]
|
||||||
error:&error
|
error:&error
|
||||||
];
|
];
|
||||||
if (error || !metal_library) {
|
if (error || !metal_library) {
|
||||||
NSLog(@"Unable to create shaders %@", error);
|
NSLog(@"Unable to create shaders %@", error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,9 +109,10 @@ NSString *g_shader_src = kShader(
|
|||||||
pipelineStateDescriptor.fragmentFunction = fragment_shader_func;
|
pipelineStateDescriptor.fragmentFunction = fragment_shader_func;
|
||||||
pipelineStateDescriptor.colorAttachments[0].pixelFormat = 80; //bgra8Unorm;
|
pipelineStateDescriptor.colorAttachments[0].pixelFormat = 80; //bgra8Unorm;
|
||||||
|
|
||||||
window_data_osx->metal.pipeline_state = [metal_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error];
|
pipeline_state = [metal_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error];
|
||||||
if (!window_data_osx->metal.pipeline_state) {
|
if (!pipeline_state) {
|
||||||
NSLog(@"Failed to created pipeline state, error %@", error);
|
NSLog(@"Failed to created pipeline state, error %@", error);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -126,8 +128,6 @@ NSString *g_shader_src = kShader(
|
|||||||
};
|
};
|
||||||
memcpy(window_data_osx->metal.vertices, s_vertices, sizeof(s_vertices));
|
memcpy(window_data_osx->metal.vertices, s_vertices, sizeof(s_vertices));
|
||||||
|
|
||||||
// Indicate that each pixel has a blue, green, red, and alpha channel, where each channel is
|
|
||||||
// an 8-bit unsigned normalized value (i.e. 0 maps to 0.0 and 255 maps to 1.0)
|
|
||||||
MTLTextureDescriptor *td;
|
MTLTextureDescriptor *td;
|
||||||
td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
|
td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
|
||||||
width:window_data->buffer_width
|
width:window_data->buffer_width
|
||||||
@ -141,36 +141,34 @@ NSString *g_shader_src = kShader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
- (void) drawInMTKView:(nonnull MTKView *)view {
|
- (void) drawInMTKView:(nonnull MTKView *) view {
|
||||||
// Wait to ensure only MaxBuffersInFlight number of frames are getting proccessed
|
// Wait to ensure only MaxBuffersInFlight number of frames are getting proccessed
|
||||||
// by any stage in the Metal pipeline (App, Metal, Drivers, GPU, etc)
|
// by any stage in the Metal pipeline (App, Metal, Drivers, GPU, etc)
|
||||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||||
|
|
||||||
// Iterate through our Metal buffers, and cycle back to the first when we've written to MaxBuffersInFlight
|
|
||||||
current_buffer = (current_buffer + 1) % MaxBuffersInFlight;
|
current_buffer = (current_buffer + 1) % MaxBuffersInFlight;
|
||||||
|
|
||||||
// Calculate the number of bytes per row of our image.
|
|
||||||
MTLRegion region = { { 0, 0, 0 }, { window_data->buffer_width, window_data->buffer_height, 1 } };
|
|
||||||
|
|
||||||
// Copy the bytes from our data object into the texture
|
|
||||||
[texture_buffers[current_buffer] replaceRegion:region mipmapLevel:0 withBytes:window_data->draw_buffer bytesPerRow:window_data->buffer_stride];
|
|
||||||
|
|
||||||
// Create a new command buffer for each render pass to the current drawable
|
// Create a new command buffer for each render pass to the current drawable
|
||||||
id<MTLCommandBuffer> commandBuffer = [window_data_osx->metal.command_queue commandBuffer];
|
id<MTLCommandBuffer> commandBuffer = [command_queue commandBuffer];
|
||||||
commandBuffer.label = @"minifb_command_buffer";
|
commandBuffer.label = @"minifb_command_buffer";
|
||||||
|
|
||||||
// Add completion hander which signals _inFlightSemaphore when Metal and the GPU has fully
|
// Add completion hander which signals semaphore when Metal and the GPU has fully
|
||||||
// finished processing the commands we're encoding this frame. This indicates when the
|
// finished processing the commands we're encoding this frame. This indicates when the
|
||||||
// dynamic buffers filled with our vertices, that we're writing to this frame, will no longer
|
// dynamic buffers filled with our vertices, that we're writing to this frame, will no longer
|
||||||
// be needed by Metal and the GPU, meaning we can overwrite the buffer contents without
|
// be needed by Metal and the GPU, meaning we can overwrite the buffer contents without
|
||||||
// corrupting the rendering.
|
// corrupting the rendering.
|
||||||
__block dispatch_semaphore_t block_sema = semaphore;
|
__block dispatch_semaphore_t block_sema = semaphore;
|
||||||
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer)
|
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
|
||||||
{
|
(void)buffer;
|
||||||
(void)buffer;
|
|
||||||
dispatch_semaphore_signal(block_sema);
|
dispatch_semaphore_signal(block_sema);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
// Copy the bytes from our data object into the texture
|
||||||
|
MTLRegion region = { { 0, 0, 0 }, { window_data->buffer_width, window_data->buffer_height, 1 } };
|
||||||
|
[texture_buffers[current_buffer] replaceRegion:region mipmapLevel:0 withBytes:window_data->draw_buffer bytesPerRow:window_data->buffer_stride];
|
||||||
|
|
||||||
|
// Delay getting the currentRenderPassDescriptor until absolutely needed. This avoids
|
||||||
|
// holding onto the drawable and blocking the display pipeline any longer than necessary
|
||||||
MTLRenderPassDescriptor* renderPassDescriptor = view.currentRenderPassDescriptor;
|
MTLRenderPassDescriptor* renderPassDescriptor = view.currentRenderPassDescriptor;
|
||||||
if (renderPassDescriptor != nil) {
|
if (renderPassDescriptor != nil) {
|
||||||
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
|
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
|
||||||
@ -180,8 +178,7 @@ NSString *g_shader_src = kShader(
|
|||||||
renderEncoder.label = @"minifb_command_encoder";
|
renderEncoder.label = @"minifb_command_encoder";
|
||||||
|
|
||||||
// Set render command encoder state
|
// Set render command encoder state
|
||||||
[renderEncoder setRenderPipelineState:window_data_osx->metal.pipeline_state];
|
[renderEncoder setRenderPipelineState:pipeline_state];
|
||||||
|
|
||||||
[renderEncoder setVertexBytes:window_data_osx->metal.vertices length:sizeof(window_data_osx->metal.vertices) atIndex:0];
|
[renderEncoder setVertexBytes:window_data_osx->metal.vertices length:sizeof(window_data_osx->metal.vertices) atIndex:0];
|
||||||
|
|
||||||
[renderEncoder setFragmentTexture:texture_buffers[current_buffer] atIndex:0];
|
[renderEncoder setFragmentTexture:texture_buffers[current_buffer] atIndex:0];
|
||||||
@ -209,4 +206,4 @@ NSString *g_shader_src = kShader(
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -24,9 +24,9 @@
|
|||||||
{
|
{
|
||||||
[self setOpaque:YES];
|
[self setOpaque:YES];
|
||||||
[self setBackgroundColor:[NSColor clearColor]];
|
[self setBackgroundColor:[NSColor clearColor]];
|
||||||
|
|
||||||
self.delegate = self;
|
self.delegate = self;
|
||||||
|
|
||||||
self->window_data = windowData;
|
self->window_data = windowData;
|
||||||
OSXView *view = (OSXView *) self->childContentView.superview;
|
OSXView *view = (OSXView *) self->childContentView.superview;
|
||||||
view->window_data = windowData;
|
view->window_data = windowData;
|
||||||
@ -59,12 +59,12 @@
|
|||||||
NSSize childBoundsSize = [childContentView bounds].size;
|
NSSize childBoundsSize = [childContentView bounds].size;
|
||||||
sizeDelta.width -= childBoundsSize.width;
|
sizeDelta.width -= childBoundsSize.width;
|
||||||
sizeDelta.height -= childBoundsSize.height;
|
sizeDelta.height -= childBoundsSize.height;
|
||||||
|
|
||||||
OSXView *frameView = [super contentView];
|
OSXView *frameView = [super contentView];
|
||||||
NSSize newFrameSize = [frameView bounds].size;
|
NSSize newFrameSize = [frameView bounds].size;
|
||||||
newFrameSize.width += sizeDelta.width;
|
newFrameSize.width += sizeDelta.width;
|
||||||
newFrameSize.height += sizeDelta.height;
|
newFrameSize.height += sizeDelta.height;
|
||||||
|
|
||||||
[super setContentSize:newFrameSize];
|
[super setContentSize:newFrameSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,7 +164,7 @@
|
|||||||
|
|
||||||
if(window_data != 0x0) {
|
if(window_data != 0x0) {
|
||||||
NSString *characters;
|
NSString *characters;
|
||||||
NSUInteger length;
|
NSUInteger length;
|
||||||
|
|
||||||
if ([string isKindOfClass:[NSAttributedString class]])
|
if ([string isKindOfClass:[NSAttributedString class]])
|
||||||
characters = [string string];
|
characters = [string string];
|
||||||
@ -212,10 +212,10 @@
|
|||||||
if (!frameView)
|
if (!frameView)
|
||||||
{
|
{
|
||||||
frameView = [[[OSXView alloc] initWithFrame:bounds] autorelease];
|
frameView = [[[OSXView alloc] initWithFrame:bounds] autorelease];
|
||||||
|
|
||||||
[super setContentView:frameView];
|
[super setContentView:frameView];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (childContentView)
|
if (childContentView)
|
||||||
{
|
{
|
||||||
[childContentView removeFromSuperview];
|
[childContentView removeFromSuperview];
|
||||||
|
@ -16,12 +16,10 @@ typedef struct Vertex {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
OSXWindow *window;
|
OSXWindow *window;
|
||||||
struct mfb_timer *timer;
|
struct mfb_timer *timer;
|
||||||
|
|
||||||
#if defined(USE_METAL_API)
|
#if defined(USE_METAL_API)
|
||||||
struct {
|
struct {
|
||||||
id<MTLCommandQueue> command_queue;
|
|
||||||
id<MTLRenderPipelineState> pipeline_state;
|
|
||||||
Vertex vertices[4];
|
Vertex vertices[4];
|
||||||
} metal;
|
} metal;
|
||||||
#endif
|
#endif
|
||||||
} SWindowData_OSX;
|
} SWindowData_OSX;
|
||||||
|
Loading…
Reference in New Issue
Block a user