Metal projection matrix test.
							parent
							
								
									0fceec19a9
								
							
						
					
					
						commit
						b52f1cee24
					
				| 
						 | 
				
			
			@ -380,11 +380,12 @@ build(Arena *arena, u32 flags, u32 arch, char *code_path, char **code_files, cha
 | 
			
		|||
 | 
			
		||||
#if OS_MAC
 | 
			
		||||
 | 
			
		||||
# define CLANG_OPTS                                   \
 | 
			
		||||
"-Wno-write-strings -Wno-deprecated-declarations "  \
 | 
			
		||||
"-Wno-comment -Wno-switch -Wno-null-dereference "   \
 | 
			
		||||
"-Wno-tautological-compare "                        \
 | 
			
		||||
"-Wno-unused-result -Wno-missing-declarations -std=c++11 "
 | 
			
		||||
# define CLANG_OPTS \
 | 
			
		||||
"-Wno-write-strings -Wno-deprecated-declarations " \
 | 
			
		||||
"-Wno-comment -Wno-switch -Wno-null-dereference " \
 | 
			
		||||
"-Wno-tautological-compare -Wno-unused-result " \
 | 
			
		||||
"-Wno-missing-declarations -Wno-nullability-completeness " \
 | 
			
		||||
"-std=c++11 "
 | 
			
		||||
 | 
			
		||||
#define CLANG_LIBS_COMMON \
 | 
			
		||||
"-framework Cocoa -framework QuartzCore " \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,12 +5,88 @@
 | 
			
		|||
#import <simd/simd.h>
 | 
			
		||||
#import <MetalKit/MetalKit.h>
 | 
			
		||||
 | 
			
		||||
// Header shared between C code here, which executes Metal API commands, and .metal files, which
 | 
			
		||||
// uses these types as inputs to the shaders.
 | 
			
		||||
#import "AAPLShaderTypes.h"
 | 
			
		||||
 | 
			
		||||
#include "AAPLShaderTypes.h"
 | 
			
		||||
#define function static
 | 
			
		||||
#define clamp(a,x,b) clamp_((a),(x),(b))
 | 
			
		||||
 | 
			
		||||
struct Metal_Renderer{
 | 
			
		||||
    MTKView *view;
 | 
			
		||||
    
 | 
			
		||||
    id<MTLDevice> device;
 | 
			
		||||
    id<MTLRenderPipelineState> pipeline_state;
 | 
			
		||||
    id<MTLCommandQueue> command_queue;
 | 
			
		||||
    id<MTLBuffer> buffer;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
global_const u32 metal_max_vertices = (1<<16);
 | 
			
		||||
 | 
			
		||||
global_const char *metal__shaders_source = R"(
 | 
			
		||||
#include <metal_stdlib>
 | 
			
		||||
#include <simd/simd.h>
 | 
			
		||||
 | 
			
		||||
using namespace metal;
 | 
			
		||||
 | 
			
		||||
// Buffer index values shared between shader and C code to ensure Metal shader buffer inputs
 | 
			
		||||
// match Metal API buffer set calls.
 | 
			
		||||
typedef enum AAPLVertexInputIndex
 | 
			
		||||
{
 | 
			
		||||
    AAPLVertexInputIndexVertices     = 0,
 | 
			
		||||
    AAPLVertexInputIndexViewportSize = 1,
 | 
			
		||||
} AAPLVertexInputIndex;
 | 
			
		||||
 | 
			
		||||
//  This structure defines the layout of vertices sent to the vertex
 | 
			
		||||
//  shader. This header is shared between the .metal shader and C code, to guarantee that
 | 
			
		||||
//  the layout of the vertex array in the C code matches the layout that the .metal
 | 
			
		||||
//  vertex shader expects.
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
    vector_float2 position;
 | 
			
		||||
    vector_float4 color;
 | 
			
		||||
} AAPLVertex;
 | 
			
		||||
 | 
			
		||||
// Vertex shader outputs and fragment shader inputs
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
    // The [[position]] attribute of this member indicates that this value
 | 
			
		||||
    // is the clip space position of the vertex when this structure is
 | 
			
		||||
    // returned from the vertex function.
 | 
			
		||||
    float4 position [[position]];
 | 
			
		||||
    
 | 
			
		||||
    // Since this member does not have a special attribute, the rasterizer
 | 
			
		||||
    // interpolates its value with the values of the other triangle vertices
 | 
			
		||||
    // and then passes the interpolated value to the fragment shader for each
 | 
			
		||||
    // fragment in the triangle.
 | 
			
		||||
    float4 color;
 | 
			
		||||
    
 | 
			
		||||
} RasterizerData;
 | 
			
		||||
 | 
			
		||||
vertex RasterizerData
 | 
			
		||||
vertexShader(uint vertexID [[vertex_id]],
 | 
			
		||||
             constant AAPLVertex *vertices [[buffer(AAPLVertexInputIndexVertices)]],
 | 
			
		||||
             constant float4x4 &projMatrix[[buffer(AAPLVertexInputIndexViewportSize)]])
 | 
			
		||||
{
 | 
			
		||||
    RasterizerData out;
 | 
			
		||||
    
 | 
			
		||||
    // Index into the array of positions to get the current vertex.
 | 
			
		||||
    // The positions are specified in pixel dimensions (i.e. a value of 100
 | 
			
		||||
    // is 100 pixels from the origin).
 | 
			
		||||
    float2 pixelSpacePosition = vertices[vertexID].position.xy;
 | 
			
		||||
    
 | 
			
		||||
    // To convert from positions in pixel space to positions in clip-space,
 | 
			
		||||
    //  divide the pixel coordinates by half the size of the viewport.
 | 
			
		||||
    out.position = float4(pixelSpacePosition, 0.0, 1.0) * projMatrix;
 | 
			
		||||
    
 | 
			
		||||
    // Pass the input color directly to the rasterizer.
 | 
			
		||||
    out.color = vertices[vertexID].color;
 | 
			
		||||
    
 | 
			
		||||
    return out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fragment float4 fragmentShader(RasterizerData in [[stage_in]])
 | 
			
		||||
{
 | 
			
		||||
    // Return the interpolated color.
 | 
			
		||||
    return in.color;
 | 
			
		||||
}
 | 
			
		||||
)";
 | 
			
		||||
 | 
			
		||||
@interface FCoderMetalRenderer : NSObject<MTKViewDelegate>
 | 
			
		||||
- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView;
 | 
			
		||||
| 
						 | 
				
			
			@ -133,4 +209,161 @@
 | 
			
		|||
    // Finalize rendering here & push the command buffer to the GPU.
 | 
			
		||||
    [commandBuffer commit];
 | 
			
		||||
}
 | 
			
		||||
@end
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
function b32
 | 
			
		||||
metal_init(Metal_Renderer *renderer, MTKView *view){
 | 
			
		||||
    NSError *error = nil;
 | 
			
		||||
    
 | 
			
		||||
    renderer->view = view;
 | 
			
		||||
    renderer->device = view.device;
 | 
			
		||||
    
 | 
			
		||||
    // NOTE(yuval): Compile the shaders
 | 
			
		||||
    id<MTLFunction> vertex_function = nil;
 | 
			
		||||
    id<MTLFunction> fragment_function = nil;
 | 
			
		||||
    {
 | 
			
		||||
        NSString *shaders_source_str = [NSString stringWithUTF8String:metal__shaders_source];
 | 
			
		||||
        
 | 
			
		||||
        MTLCompileOptions *options = [[MTLCompileOptions alloc] init];
 | 
			
		||||
        options.fastMathEnabled = YES;
 | 
			
		||||
        
 | 
			
		||||
        id<MTLLibrary> shader_library = [renderer->device newLibraryWithSource:shaders_source_str
 | 
			
		||||
                options:options error:&error];
 | 
			
		||||
        vertex_function = [shader_library newFunctionWithName:@"vertexShader"];
 | 
			
		||||
        fragment_function = [shader_library newFunctionWithName:@"fragmentShader"];
 | 
			
		||||
        
 | 
			
		||||
        [options release];
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (error != nil){
 | 
			
		||||
        return(false);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // NOTE(yuval): Configure the pipeline descriptor
 | 
			
		||||
    {
 | 
			
		||||
        MTLRenderPipelineDescriptor *pipeline_state_descriptor = [[MTLRenderPipelineDescriptor alloc] init];
 | 
			
		||||
        pipeline_state_descriptor.label = @"4coder Metal Renderer Pipeline";
 | 
			
		||||
        pipeline_state_descriptor.vertexFunction = vertex_function;
 | 
			
		||||
        pipeline_state_descriptor.fragmentFunction = fragment_function;
 | 
			
		||||
        pipeline_state_descriptor.colorAttachments[0].pixelFormat = view.colorPixelFormat;
 | 
			
		||||
        
 | 
			
		||||
        renderer->pipeline_state = [renderer->device newRenderPipelineStateWithDescriptor:pipeline_state_descriptor
 | 
			
		||||
                error:&error];
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (error != nil){
 | 
			
		||||
        return(false);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // NOTE(yuval): Create the command queue
 | 
			
		||||
    renderer->command_queue = [renderer->device newCommandQueue];
 | 
			
		||||
    
 | 
			
		||||
    // NOTE(yuval): Create the vertex buffer
 | 
			
		||||
    {
 | 
			
		||||
        u32 buffer_size = (metal_max_vertices * sizeof(Render_Vertex));
 | 
			
		||||
        MTLResourceOptions options = MTLCPUCacheModeWriteCombined|MTLResourceStorageModeManaged;
 | 
			
		||||
        renderer->buffer = [renderer->device newBufferWithLength:buffer_size
 | 
			
		||||
                options:options];
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function void
 | 
			
		||||
metal_render(Metal_Renderer *renderer, Render_Target *t){
 | 
			
		||||
    static const AAPLVertex triangleVertices[] = {
 | 
			
		||||
        // 2D positions,    RGBA colors
 | 
			
		||||
        { {  200,  100 }, { 1, 0, 0, 1 } },
 | 
			
		||||
        { { 100,  100 }, { 0, 1, 0, 1 } },
 | 
			
		||||
        { {    150, 200  }, { 0, 0, 1, 1 } },
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    // NOTE(yuval): Create the command buffer
 | 
			
		||||
    id<MTLCommandBuffer> command_buffer = [renderer->command_queue commandBuffer];
 | 
			
		||||
    command_buffer.label = @"4coder Metal Render Command";
 | 
			
		||||
    
 | 
			
		||||
    // NOTE(yuval): Obtain the render pass descriptor from the renderer's view
 | 
			
		||||
    MTLRenderPassDescriptor *render_pass_descriptor = renderer->view.currentRenderPassDescriptor;
 | 
			
		||||
    if (render_pass_descriptor != nil){
 | 
			
		||||
        // NOTE(yuval): Create the render command encoder
 | 
			
		||||
        id<MTLRenderCommandEncoder> render_encoder
 | 
			
		||||
            = [command_buffer renderCommandEncoderWithDescriptor:render_pass_descriptor];
 | 
			
		||||
        render_encoder.label = @"4coder Render Encoder";
 | 
			
		||||
        
 | 
			
		||||
        // NOTE(yuval): Set the region of the drawable to draw into
 | 
			
		||||
        [render_encoder setViewport:(MTLViewport){0.0, 0.0, (double)t->width, (double)t->height, 0.0, 1.0}];
 | 
			
		||||
        
 | 
			
		||||
        // NOTE(yuval): Set the render pipeline to use for drawing
 | 
			
		||||
        [render_encoder setRenderPipelineState:renderer->pipeline_state];
 | 
			
		||||
        
 | 
			
		||||
        // NOTE(yuval): Pass in the parameter data
 | 
			
		||||
        [render_encoder setVertexBytes:triangleVertices
 | 
			
		||||
                length:sizeof(triangleVertices)
 | 
			
		||||
                atIndex:AAPLVertexInputIndexVertices];
 | 
			
		||||
        
 | 
			
		||||
#if 0
 | 
			
		||||
        vector_uint2 viewport_size = {(u32)t->width, (u32)t->height};
 | 
			
		||||
        [render_encoder setVertexBytes:&viewport_size
 | 
			
		||||
                length:sizeof(viewport_size)
 | 
			
		||||
                atIndex:AAPLVertexInputIndexViewportSize];
 | 
			
		||||
#else
 | 
			
		||||
        float left = 0, right = (float)t->width;
 | 
			
		||||
        float bottom = 0, top = (float)t->height;
 | 
			
		||||
        float near_depth = -1.0f, far_depth = 1.0f;
 | 
			
		||||
        float m[16] = {
 | 
			
		||||
            2.0f / (right - left), 0.0f, 0.0f, 0.0f,
 | 
			
		||||
            0.0f, 2.0f / (top - bottom), 0.0f, 0.0f,
 | 
			
		||||
            0.0f, 0.0f, -1.0f / (far_depth - near_depth), 0.0f,
 | 
			
		||||
            -((right + left) / (right - left)), -((top + bottom) / (top - bottom)),
 | 
			
		||||
            (-near_depth) * (far_depth - near_depth), 1.0f
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        float sLength = 1.0f / (right - left);
 | 
			
		||||
        float sHeight = 1.0f / (top   - bottom);
 | 
			
		||||
        float sDepth  = 1.0f / (far_depth   - near_depth);
 | 
			
		||||
        
 | 
			
		||||
        simd::float4 P;
 | 
			
		||||
        simd::float4 Q;
 | 
			
		||||
        simd::float4 R;
 | 
			
		||||
        simd::float4 S;
 | 
			
		||||
        
 | 
			
		||||
        P.x = 2.0f * sLength;
 | 
			
		||||
        P.y = 0.0f;
 | 
			
		||||
        P.z = 0.0f;
 | 
			
		||||
        P.w = -((right + left) / (right - left));
 | 
			
		||||
        
 | 
			
		||||
        Q.x = 0.0f;
 | 
			
		||||
        Q.y = 2.0f * sHeight;
 | 
			
		||||
        Q.z = 0.0f;
 | 
			
		||||
        Q.w = -((top + bottom) / (top - bottom));
 | 
			
		||||
        
 | 
			
		||||
        R.x = 0.0f;
 | 
			
		||||
        R.y = 0.0f;
 | 
			
		||||
        R.z = sDepth;
 | 
			
		||||
        R.w = -near_depth  * sDepth;
 | 
			
		||||
        
 | 
			
		||||
        S.x =  0.0f;
 | 
			
		||||
        S.y =  0.0f;
 | 
			
		||||
        S.z =  0.0f;
 | 
			
		||||
        S.w =  1.0f;
 | 
			
		||||
        
 | 
			
		||||
        simd_float4x4 proj = simd::float4x4(P, Q, R, S);
 | 
			
		||||
        
 | 
			
		||||
        [render_encoder setVertexBytes:&proj
 | 
			
		||||
                length:sizeof(proj)
 | 
			
		||||
                atIndex:AAPLVertexInputIndexViewportSize];
 | 
			
		||||
#endif
 | 
			
		||||
        
 | 
			
		||||
        // NOTE(yuval): Draw the triangle
 | 
			
		||||
        [render_encoder drawPrimitives:MTLPrimitiveTypeTriangle
 | 
			
		||||
                vertexStart:0
 | 
			
		||||
                vertexCount:3];
 | 
			
		||||
        
 | 
			
		||||
        [render_encoder endEncoding];
 | 
			
		||||
        
 | 
			
		||||
        // NOTE(yuval): Schedule a present once the framebuffer is complete using the current drawable
 | 
			
		||||
        [command_buffer presentDrawable:renderer->view.currentDrawable];
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    [command_buffer commit];
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
#import "metal/4ed_metal_render.mm"
 | 
			
		||||
 | 
			
		||||
global Metal_Renderer metal_renderer;
 | 
			
		||||
global MTKView *metal_view;
 | 
			
		||||
global FCoderMetalRenderer *metal_renderer;
 | 
			
		||||
 | 
			
		||||
function void
 | 
			
		||||
mac_metal_init(NSWindow *window){
 | 
			
		||||
| 
						 | 
				
			
			@ -17,13 +17,15 @@ mac_metal_init(NSWindow *window){
 | 
			
		|||
    [content_view addSubview:metal_view];
 | 
			
		||||
    
 | 
			
		||||
    // NOTE(yuval): Create the Metal renderer
 | 
			
		||||
    metal_renderer = [[FCoderMetalRenderer alloc] initWithMetalKitView:metal_view];
 | 
			
		||||
    //metal_renderer = [[FCoderMetalRenderer alloc] initWithMetalKitView:metal_view];
 | 
			
		||||
    metal_init(&metal_renderer, metal_view);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function void
 | 
			
		||||
mac_metal_render(Render_Target* target){
 | 
			
		||||
    u64 begin_time = system_now_time();
 | 
			
		||||
    [metal_renderer drawInMTKView:metal_view];
 | 
			
		||||
    //[metal_renderer drawInMTKView:metal_view];
 | 
			
		||||
    metal_render(&metal_renderer, target);
 | 
			
		||||
    u64 end_time = system_now_time();
 | 
			
		||||
    printf("Metal Render Time: %fs\n\n", mac_get_time_diff_sec(begin_time, end_time));
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue