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