unify a little bit more iOS & MacOS

This commit is contained in:
Carlos Aragones
2020-05-17 19:48:59 +02:00
parent 75de20e4cc
commit 80a7a33b7c
9 changed files with 146 additions and 131 deletions

View File

@ -11,7 +11,7 @@
SWindowData *
create_window_data(unsigned width, unsigned height) {
SWindowData *window_data;
window_data = malloc(sizeof(SWindowData));
if(window_data == 0x0) {
NSLog(@"Cannot allocate window data");
@ -48,7 +48,7 @@ create_window_data(unsigned width, unsigned height) {
NSLog(@"Unable to create draw buffer");
return 0x0;
}
return window_data;
}
@ -67,20 +67,11 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags)
kUnused(title);
kUnused(flags);
SWindowData *window_data = create_window_data(width, height);
if (window_data == 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];
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];
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) {
iOSViewController *controller = [[iOSViewController alloc] initWithWindowData:window_data];
[window setRootViewController:controller];
@ -216,7 +207,7 @@ mfb_timer_tick() {
if (timebase.denom == 0) {
(void) mach_timebase_info(&timebase);
}
uint64_t time = mach_absolute_time();
//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 low = (time & 0xFFFFFFFFull) * timebase.numer / timebase.denom;
high /= timebase.denom;
return (high << 32) + highRem + low;
}

View File

@ -8,15 +8,12 @@
#import <MetalKit/MetalKit.h>
#include "WindowData.h"
#include "WindowData_IOS.h"
// Our platform independent renderer class.
// Implements the MTKViewDelegate protocol which allows it to accept per-frame
// update and drawable resize callbacks.
@interface iOSViewDelegate : NSObject <MTKViewDelegate>
{
@public SWindowData *window_data;
@public SWindowData_IOS *window_data_ios;
}
-(nonnull instancetype) initWithMetalKitView:(nonnull MTKView *) view windowData:(nonnull SWindowData *) windowData;

View File

@ -21,25 +21,23 @@
//-------------------------------------
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(
"#include <metal_stdlib>\n",
using namespace metal;
//---------------------
//-------------
struct VertexOutput {
float4 pos [[position]];
float2 texcoord;
};
//-------------
struct Vertex {
float4 position [[position]];
};
//---------------------
//-------------
vertex VertexOutput
vertFunc(unsigned int vID[[vertex_id]], const device Vertex *pos [[ buffer(0) ]]) {
VertexOutput out;
@ -52,7 +50,7 @@ NSString *g_shader_src = kShader(
return out;
}
//---------------------
//-------------
fragment float4
fragFunc(VertexOutput input [[stage_in]], texture2d<half> colorTexture [[ texture(0) ]]) {
constexpr sampler textureSampler(mag_filter::nearest, min_filter::nearest);
@ -67,29 +65,38 @@ NSString *g_shader_src = kShader(
//-------------------------------------
@implementation iOSViewDelegate {
dispatch_semaphore_t m_semaphore;
id <MTLCommandQueue> m_command_queue;
SWindowData *window_data;
SWindowData_IOS *window_data_ios;
id<MTLDevice> metal_device;
id<MTLLibrary> metal_library;
id <MTLRenderPipelineState> m_pipeline_state;
id <MTLTexture> m_texture_buffer;
dispatch_semaphore_t semaphore;
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 {
self = [super init];
if (self) {
self->window_data = windowData;
self->window_data_ios = (SWindowData_IOS *) windowData->specific;
window_data = windowData;
window_data_ios = (SWindowData_IOS *) windowData->specific;
view.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
view.sampleCount = 1;
g_metal_device = view.device;
metal_device = view.device;
m_semaphore = dispatch_semaphore_create(MaxBuffersInFlight);
m_command_queue = [g_metal_device newCommandQueue];
// Used for syncing the CPU and GPU
semaphore = dispatch_semaphore_create(MaxBuffersInFlight);
// Setup command queue
command_queue = [metal_device newCommandQueue];
[self _createShaders];
[self _createAssets];
@ -100,19 +107,19 @@ NSString *g_shader_src = kShader(
//-------------------------------------
- (bool) _createShaders {
NSError *error = nil;
g_library = [g_metal_device newLibraryWithSource:g_shader_src
options:[[MTLCompileOptions alloc] init]
error:&error
NSError *error = 0x0;
metal_library = [metal_device newLibraryWithSource:g_shader_src
options:[[MTLCompileOptions alloc] init]
error:&error
];
if (error || !g_library) {
if (error || !metal_library) {
NSLog(@"Unable to create shaders %@", error);
return false;
}
id<MTLFunction> vertex_shader_func = [g_library newFunctionWithName:@"vertFunc"];
id<MTLFunction> fragment_shader_func = [g_library newFunctionWithName:@"fragFunc"];
id<MTLFunction> vertex_shader_func = [metal_library newFunctionWithName:@"vertFunc"];
id<MTLFunction> fragment_shader_func = [metal_library newFunctionWithName:@"fragFunc"];
if (!vertex_shader_func) {
NSLog(@"Unable to get vertFunc!\n");
@ -124,14 +131,15 @@ NSString *g_shader_src = kShader(
return false;
}
// Create a reusable pipeline state
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
pipelineStateDescriptor.label = @"MiniFB_pipeline";
pipelineStateDescriptor.vertexFunction = vertex_shader_func;
pipelineStateDescriptor.fragmentFunction = fragment_shader_func;
pipelineStateDescriptor.colorAttachments[0].pixelFormat = 80; //bgra8Unorm;
m_pipeline_state = [g_metal_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error];
if (!m_pipeline_state) {
pipeline_state = [metal_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error];
if (!pipeline_state) {
NSLog(@"Failed to created pipeline state, error %@", error);
return false;
}
@ -141,26 +149,42 @@ NSString *g_shader_src = kShader(
//-------------------------------------
- (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;
td = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
width:window_data->buffer_width
height:window_data->buffer_height
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 {
// Per frame updates here
dispatch_semaphore_wait(m_semaphore, DISPATCH_TIME_FOREVER);
// Wait to ensure only MaxBuffersInFlight number of frames are getting proccessed
// 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";
__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) {
(void)buffer;
dispatch_semaphore_signal(block_sema);
@ -168,7 +192,7 @@ NSString *g_shader_src = kShader(
// Copy the bytes from our data object into the texture
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
// 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";
// 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 setFragmentTexture:m_texture_buffers[m_current_buffer] atIndex:0];
[renderEncoder setFragmentTexture:m_texture_buffer atIndex:0];
//[renderEncoder setFragmentTexture:texture_buffers[current_buffer] atIndex:0];
[renderEncoder setFragmentTexture:texture_buffer atIndex:0];
// Draw the vertices of our quads
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];