Work on metal renderer. Only semi-working for now.
							parent
							
								
									813ba593e3
								
							
						
					
					
						commit
						efad772401
					
				|  | @ -15,6 +15,7 @@ struct Metal_Renderer{ | ||||||
|     id<MTLRenderPipelineState> pipeline_state; |     id<MTLRenderPipelineState> pipeline_state; | ||||||
|     id<MTLCommandQueue> command_queue; |     id<MTLCommandQueue> command_queue; | ||||||
|     id<MTLBuffer> buffer; |     id<MTLBuffer> buffer; | ||||||
|  |     id<MTLCaptureScope> capture_scope; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| global_const u32 metal_max_vertices = (1<<16); | global_const u32 metal_max_vertices = (1<<16); | ||||||
|  | @ -25,193 +26,94 @@ global_const char *metal__shaders_source = R"( | ||||||
| 
 | 
 | ||||||
| using namespace metal; | 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 | typedef struct{ | ||||||
| //  shader. This header is shared between the .metal shader and C code, to guarantee that | packed_float2 xy; | ||||||
| //  the layout of the vertex array in the C code matches the layout that the .metal |     packed_float3 uvw; | ||||||
| //  vertex shader expects. | uint32_t color; | ||||||
| typedef struct | float half_thickness; | ||||||
| { | } Vertex; | ||||||
|     vector_float2 position; |  | ||||||
|     vector_float4 color; |  | ||||||
| } AAPLVertex; |  | ||||||
| 
 | 
 | ||||||
| // Vertex shader outputs and fragment shader inputs | // NOTE(yuval): Vertex shader outputs and fragment shader inputs | ||||||
| typedef struct | typedef struct{ | ||||||
| { | // NOTE(yuval): Vertex shader output | ||||||
|     // The [[position]] attribute of this member indicates that this value | float4 position [[position]]; | ||||||
|     // is the clip space position of the vertex when this structure is | 
 | ||||||
|     // returned from the vertex function. | // NOTE(yuval): Fragment shader inputs | ||||||
|     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; |     float4 color; | ||||||
|      |     float3 uvw; | ||||||
| } RasterizerData; |     float2 xy; | ||||||
|  |     float2 adjusted_half_dim; | ||||||
|  |     float half_thickness; | ||||||
|  | } Rasterizer_Data; | ||||||
| 
 | 
 | ||||||
| vertex RasterizerData | //////////////////////////////// | ||||||
| vertexShader(uint vertexID [[vertex_id]], | 
 | ||||||
|              constant AAPLVertex *vertices [[buffer(AAPLVertexInputIndexVertices)]], | vertex Rasterizer_Data | ||||||
|              constant float4x4 &projMatrix[[buffer(AAPLVertexInputIndexViewportSize)]]) | vertex_shader(uint vertex_id [[vertex_id]], constant Vertex *vertices [[buffer(0)]], | ||||||
| { | constant float4x4 &proj [[buffer(1)]]){ | ||||||
|     RasterizerData out; |     constant Vertex *in = &vertices[vertex_id]; | ||||||
|  |     Rasterizer_Data out; | ||||||
|      |      | ||||||
|     // Index into the array of positions to get the current vertex. |     // NOTE(yuval): Calculate position in NDC | ||||||
|     // The positions are specified in pixel dimensions (i.e. a value of 100 |     out.position = proj * float4(in->xy, 0.0, 1.0); | ||||||
|     // is 100 pixels from the origin). |  | ||||||
|     float2 pixelSpacePosition = vertices[vertexID].position.xy; |  | ||||||
|      |      | ||||||
|     // To convert from positions in pixel space to positions in clip-space, |     // NOTE(yuval): Convert color to float4 format | ||||||
|     //  divide the pixel coordinates by half the size of the viewport. |     out.color.b = ((float((in->color       ) & 0xFFu)) / 255.0); | ||||||
|     out.position = projMatrix * float4(pixelSpacePosition, 0.0, 1.0); |     out.color.g = ((float((in->color >>  8u) & 0xFFu)) / 255.0); | ||||||
|  |     out.color.r = ((float((in->color >> 16u) & 0xFFu)) / 255.0); | ||||||
|  |     out.color.a = ((float((in->color >> 24u) & 0xFFu)) / 255.0); | ||||||
|      |      | ||||||
|     // Pass the input color directly to the rasterizer. |     // NOTE(yuval): Pass uvw coordinates to the fragment shader | ||||||
|     out.color = vertices[vertexID].color; |     out.uvw = in->uvw; | ||||||
|      |      | ||||||
|     return out; |     // NOTE(yuval): Calculate adjusted half dim | ||||||
|  |     float2 center = in->uvw.xy; | ||||||
|  |     float2 half_dim = abs(in->xy - center); | ||||||
|  |     out.adjusted_half_dim = (half_dim - in->uvw.zz + float2(0.5, 0.5)); | ||||||
|  |      | ||||||
|  |     // NOTE(yuval): Pass half_thickness to the fragment shader | ||||||
|  |     out.half_thickness = in->half_thickness; | ||||||
|  |      | ||||||
|  |     // NOTE(yuval): Pass xy to the fragment shader | ||||||
|  |     out.xy = in->xy; | ||||||
|  |      | ||||||
|  |     return(out); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fragment float4 fragmentShader(RasterizerData in [[stage_in]]) | //////////////////////////////// | ||||||
| { | 
 | ||||||
|     // Return the interpolated color. | float | ||||||
|     return in.color; | rectangle_sd(float2 p, float2 b){ | ||||||
|  | float2 d = (abs(p) - b); | ||||||
|  | float result = (length(max(d, float2(0.0, 0.0))) + min(max(d.x, d.y), 0.0)); | ||||||
|  | 
 | ||||||
|  | return(result); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fragment float4 | ||||||
|  | fragment_shader(Rasterizer_Data in [[stage_in]]){ | ||||||
|  | float has_thickness = step(0.49, in.half_thickness); | ||||||
|  | // float does_not_have_thickness = (1.0 - has_thickness); | ||||||
|  | 
 | ||||||
|  | // TODO(yuval): Sample texture here. | ||||||
|  | 
 | ||||||
|  | float2 center = in.uvw.xy; | ||||||
|  | float roundness = in.uvw.z; | ||||||
|  | float sd = rectangle_sd(in.xy - center, in.adjusted_half_dim); | ||||||
|  | sd = sd - roundness; | ||||||
|  | sd = (abs(sd + in.half_thickness) - in.half_thickness); | ||||||
|  | float shape_value = (1.0 - smoothstep(-1.0, 0.0, sd)); | ||||||
|  | shape_value *= has_thickness; | ||||||
|  | 
 | ||||||
|  |     // TOOD(yuval): Add sample_value to alpha | ||||||
|  |    float4 out_color = in.color;// float4(in.color.xyz, in.color.a * (shape_value)); | ||||||
|  |     return(out_color); | ||||||
| } | } | ||||||
| )"; | )"; | ||||||
| 
 | 
 | ||||||
| @interface FCoderMetalRenderer : NSObject<MTKViewDelegate> | function void | ||||||
| - (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView; |  | ||||||
| @end |  | ||||||
| 
 |  | ||||||
| @implementation FCoderMetalRenderer{ |  | ||||||
|     id<MTLDevice> _device; |  | ||||||
|      |  | ||||||
|     // The render pipeline generated from the vertex and fragment shaders in the .metal shader file. |  | ||||||
|     id<MTLRenderPipelineState> _pipelineState; |  | ||||||
|      |  | ||||||
|     // The command queue used to pass commands to the device. |  | ||||||
|     id<MTLCommandQueue> _commandQueue; |  | ||||||
|      |  | ||||||
|     // The current size of the view, used as an input to the vertex shader. |  | ||||||
|     vector_uint2 _viewportSize; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| - (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView{ |  | ||||||
|     self = [super init]; |  | ||||||
|     if(self) |  | ||||||
|     { |  | ||||||
|         NSError *error = nil; |  | ||||||
|          |  | ||||||
|         _device = mtkView.device; |  | ||||||
|          |  | ||||||
|         // Load all the shader files with a .metal file extension in the project. |  | ||||||
|         id<MTLLibrary> defaultLibrary = [_device newLibraryWithFile:@"shaders/AAPLShaders.metallib" |  | ||||||
|                 error:&error]; |  | ||||||
|         Assert(error == nil); |  | ||||||
|          |  | ||||||
|         id<MTLFunction> vertexFunction = [defaultLibrary newFunctionWithName:@"vertexShader"]; |  | ||||||
|         id<MTLFunction> fragmentFunction = [defaultLibrary newFunctionWithName:@"fragmentShader"]; |  | ||||||
|          |  | ||||||
|         // Configure a pipeline descriptor that is used to create a pipeline state. |  | ||||||
|         MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; |  | ||||||
|         pipelineStateDescriptor.label = @"Simple Pipeline"; |  | ||||||
|         pipelineStateDescriptor.vertexFunction = vertexFunction; |  | ||||||
|         pipelineStateDescriptor.fragmentFunction = fragmentFunction; |  | ||||||
|         pipelineStateDescriptor.colorAttachments[0].pixelFormat = mtkView.colorPixelFormat; |  | ||||||
|          |  | ||||||
|         _pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor |  | ||||||
|                 error:&error]; |  | ||||||
|          |  | ||||||
|         // Pipeline State creation could fail if the pipeline descriptor isn't set up properly. |  | ||||||
|         //  If the Metal API validation is enabled, you can find out more information about what |  | ||||||
|         //  went wrong.  (Metal API validation is enabled by default when a debug build is run |  | ||||||
|         //  from Xcode.) |  | ||||||
|         NSAssert(_pipelineState, @"Failed to created pipeline state: %@", error); |  | ||||||
|          |  | ||||||
|         // Create the command queue |  | ||||||
|         _commandQueue = [_device newCommandQueue]; |  | ||||||
|          |  | ||||||
|         u32 max_buffer_size = (u32)[_device maxBufferLength]; |  | ||||||
|         printf("Max Buffer Size: %u - Which is %lu vertices\n", max_buffer_size, (max_buffer_size / sizeof(Render_Vertex))); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     return self; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Called whenever view changes orientation or is resized |  | ||||||
| - (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size{ |  | ||||||
|     // Save the size of the drawable to pass to the vertex shader. |  | ||||||
|      |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Called whenever the view needs to render a frame. |  | ||||||
| - (void)drawInMTKView:(nonnull MTKView *)view{ |  | ||||||
|     CGSize size = [view drawableSize]; |  | ||||||
|     _viewportSize.x = size.width; |  | ||||||
|     _viewportSize.y = size.height; |  | ||||||
|      |  | ||||||
|     static const AAPLVertex triangleVertices[] = |  | ||||||
|     { |  | ||||||
|         // 2D positions,    RGBA colors |  | ||||||
|         { {  250,  -250 }, { 1, 0, 0, 1 } }, |  | ||||||
|         { { -250,  -250 }, { 0, 1, 0, 1 } }, |  | ||||||
|         { {    0,   250 }, { 0, 0, 1, 1 } }, |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     // Create a new command buffer for each render pass to the current drawable. |  | ||||||
|     id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer]; |  | ||||||
|     commandBuffer.label = @"MyCommand"; |  | ||||||
|      |  | ||||||
|     // Obtain a renderPassDescriptor generated from the view's drawable textures. |  | ||||||
|     MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor; |  | ||||||
|      |  | ||||||
|     if(renderPassDescriptor != nil) |  | ||||||
|     { |  | ||||||
|         // Create a render command encoder. |  | ||||||
|         id<MTLRenderCommandEncoder> renderEncoder = |  | ||||||
|             [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; |  | ||||||
|         renderEncoder.label = @"MyRenderEncoder"; |  | ||||||
|          |  | ||||||
|         // Set the region of the drawable to draw into. |  | ||||||
|         [renderEncoder setViewport:(MTLViewport){0.0, 0.0, (double)_viewportSize.x, (double)_viewportSize.y, 0.0, 1.0 }]; |  | ||||||
|          |  | ||||||
|         [renderEncoder setRenderPipelineState:_pipelineState]; |  | ||||||
|          |  | ||||||
|         // Pass in the parameter data. |  | ||||||
|         [renderEncoder setVertexBytes:triangleVertices |  | ||||||
|                 length:sizeof(triangleVertices) |  | ||||||
|                 atIndex:AAPLVertexInputIndexVertices]; |  | ||||||
|          |  | ||||||
|         [renderEncoder setVertexBytes:&_viewportSize |  | ||||||
|                 length:sizeof(_viewportSize) |  | ||||||
|                 atIndex:AAPLVertexInputIndexViewportSize]; |  | ||||||
|          |  | ||||||
|         // Draw the triangle. |  | ||||||
|         [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle |  | ||||||
|                 vertexStart:0 |  | ||||||
|                 vertexCount:3]; |  | ||||||
|          |  | ||||||
|         [renderEncoder endEncoding]; |  | ||||||
|          |  | ||||||
|         // Schedule a present once the framebuffer is complete using the current drawable. |  | ||||||
|         [commandBuffer presentDrawable:view.currentDrawable]; |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     // Finalize rendering here & push the command buffer to the GPU. |  | ||||||
|     [commandBuffer commit]; |  | ||||||
| } |  | ||||||
| @end |  | ||||||
| 
 |  | ||||||
| function b32 |  | ||||||
| metal_init(Metal_Renderer *renderer, MTKView *view){ | metal_init(Metal_Renderer *renderer, MTKView *view){ | ||||||
|     NSError *error = nil; |     NSError *error = nil; | ||||||
|      |      | ||||||
|  | @ -229,15 +131,13 @@ metal_init(Metal_Renderer *renderer, MTKView *view){ | ||||||
|          |          | ||||||
|         id<MTLLibrary> shader_library = [renderer->device newLibraryWithSource:shaders_source_str |         id<MTLLibrary> shader_library = [renderer->device newLibraryWithSource:shaders_source_str | ||||||
|                 options:options error:&error]; |                 options:options error:&error]; | ||||||
|         vertex_function = [shader_library newFunctionWithName:@"vertexShader"]; |         vertex_function = [shader_library newFunctionWithName:@"vertex_shader"]; | ||||||
|         fragment_function = [shader_library newFunctionWithName:@"fragmentShader"]; |         fragment_function = [shader_library newFunctionWithName:@"fragment_shader"]; | ||||||
|          |          | ||||||
|         [options release]; |         [options release]; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     if (error != nil){ |     Assert(error == nil); | ||||||
|         return(false); |  | ||||||
|     } |  | ||||||
|      |      | ||||||
|     // NOTE(yuval): Configure the pipeline descriptor |     // NOTE(yuval): Configure the pipeline descriptor | ||||||
|     { |     { | ||||||
|  | @ -246,14 +146,17 @@ metal_init(Metal_Renderer *renderer, MTKView *view){ | ||||||
|         pipeline_state_descriptor.vertexFunction = vertex_function; |         pipeline_state_descriptor.vertexFunction = vertex_function; | ||||||
|         pipeline_state_descriptor.fragmentFunction = fragment_function; |         pipeline_state_descriptor.fragmentFunction = fragment_function; | ||||||
|         pipeline_state_descriptor.colorAttachments[0].pixelFormat = view.colorPixelFormat; |         pipeline_state_descriptor.colorAttachments[0].pixelFormat = view.colorPixelFormat; | ||||||
|  |         pipeline_state_descriptor.colorAttachments[0].blendingEnabled = YES; | ||||||
|  |         pipeline_state_descriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; | ||||||
|  |         pipeline_state_descriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; | ||||||
|  |         pipeline_state_descriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne; | ||||||
|  |         pipeline_state_descriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; | ||||||
|          |          | ||||||
|         renderer->pipeline_state = [renderer->device newRenderPipelineStateWithDescriptor:pipeline_state_descriptor |         renderer->pipeline_state = [renderer->device newRenderPipelineStateWithDescriptor:pipeline_state_descriptor | ||||||
|                 error:&error]; |                 error:&error]; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     if (error != nil){ |     Assert(error == nil); | ||||||
|         return(false); |  | ||||||
|     } |  | ||||||
|      |      | ||||||
|     // NOTE(yuval): Create the command queue |     // NOTE(yuval): Create the command queue | ||||||
|     renderer->command_queue = [renderer->device newCommandQueue]; |     renderer->command_queue = [renderer->device newCommandQueue]; | ||||||
|  | @ -266,17 +169,20 @@ metal_init(Metal_Renderer *renderer, MTKView *view){ | ||||||
|                 options:options]; |                 options:options]; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     return(true); |     // NOTE(yuval): Create a capture scope for gpu frame capture | ||||||
|  |     renderer->capture_scope = [[MTLCaptureManager sharedCaptureManager] | ||||||
|  |             newCaptureScopeWithDevice:renderer->device]; | ||||||
|  |     renderer->capture_scope.label = @"4coder Metal Capture Scope"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function void | function void | ||||||
| metal_render(Metal_Renderer *renderer, Render_Target *t){ | metal_render(Metal_Renderer *renderer, Render_Target *t){ | ||||||
|     static const AAPLVertex triangleVertices[] = { |     [renderer->capture_scope beginScope]; | ||||||
|         // 2D positions,    RGBA colors |      | ||||||
|         { {  200,  100 }, { 1, 0, 0, 1 } }, |     i32 width = t->width; | ||||||
|         { { 100,  100 }, { 0, 1, 0, 1 } }, |     i32 height = t->height; | ||||||
|         { {    150, 200  }, { 0, 0, 1, 1 } }, |      | ||||||
|     }; |     Font_Set* font_set = (Font_Set*)t->font_set; | ||||||
|      |      | ||||||
|     // NOTE(yuval): Create the command buffer |     // NOTE(yuval): Create the command buffer | ||||||
|     id<MTLCommandBuffer> command_buffer = [renderer->command_queue commandBuffer]; |     id<MTLCommandBuffer> command_buffer = [renderer->command_queue commandBuffer]; | ||||||
|  | @ -285,79 +191,95 @@ metal_render(Metal_Renderer *renderer, Render_Target *t){ | ||||||
|     // NOTE(yuval): Obtain the render pass descriptor from the renderer's view |     // NOTE(yuval): Obtain the render pass descriptor from the renderer's view | ||||||
|     MTLRenderPassDescriptor *render_pass_descriptor = renderer->view.currentRenderPassDescriptor; |     MTLRenderPassDescriptor *render_pass_descriptor = renderer->view.currentRenderPassDescriptor; | ||||||
|     if (render_pass_descriptor != nil){ |     if (render_pass_descriptor != nil){ | ||||||
|  |         render_pass_descriptor.colorAttachments[0].clearColor = MTLClearColorMake(1.0f, 0.0f, 1.0f, 1.0f); | ||||||
|  |          | ||||||
|         // NOTE(yuval): Create the render command encoder |         // NOTE(yuval): Create the render command encoder | ||||||
|         id<MTLRenderCommandEncoder> render_encoder |         id<MTLRenderCommandEncoder> render_encoder | ||||||
|             = [command_buffer renderCommandEncoderWithDescriptor:render_pass_descriptor]; |             = [command_buffer renderCommandEncoderWithDescriptor:render_pass_descriptor]; | ||||||
|         render_encoder.label = @"4coder Render Encoder"; |         render_encoder.label = @"4coder Render Encoder"; | ||||||
|          |          | ||||||
|         // NOTE(yuval): Set the region of the drawable to draw into |         // 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}]; |         [render_encoder setViewport:(MTLViewport){0.0, 0.0, (double)width, (double)height, 0.0, 1.0}]; | ||||||
|          |          | ||||||
|         // NOTE(yuval): Set the render pipeline to use for drawing |         // NOTE(yuval): Set the render pipeline to use for drawing | ||||||
|         [render_encoder setRenderPipelineState:renderer->pipeline_state]; |         [render_encoder setRenderPipelineState:renderer->pipeline_state]; | ||||||
|          |          | ||||||
|         // NOTE(yuval): Pass in the parameter data |         // NOTE(yuval): Calculate and pass in the projection matrix | ||||||
|         [render_encoder setVertexBytes:triangleVertices |         float left = 0, right = (float)width; | ||||||
|                 length:sizeof(triangleVertices) |         float bottom = (float)height, top = 0; | ||||||
|                 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 near_depth = -1.0f, far_depth = 1.0f; | ||||||
|         float m[16] = { |         float proj[16] = { | ||||||
|             2.0f / (right - left), 0.0f, 0.0f, 0.0f, |             2.0f / (right - left), 0.0f, 0.0f, 0.0f, | ||||||
|             0.0f, 2.0f / (top - bottom), 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, |             0.0f, 0.0f, -1.0f / (far_depth - near_depth), 0.0f, | ||||||
|             -((right + left) / (right - left)), -((top + bottom) / (top - bottom)), |             -((right + left) / (right - left)), -((top + bottom) / (top - bottom)), | ||||||
|             (-near_depth) / (far_depth - near_depth), 1.0f |             -(near_depth / (far_depth - near_depth)), 1.0f | ||||||
|         }; |         }; | ||||||
|          |          | ||||||
|         float sLength = 1.0f / (right - left); |         for (Render_Group *group = t->group_first; | ||||||
|         float sHeight = 1.0f / (top   - bottom); |              group; | ||||||
|         float sDepth  = 1.0f / (far_depth   - near_depth); |              group = group->next){ | ||||||
|          |             // NOTE(yuval): Set scissor rect | ||||||
|         simd::float4 P; |             { | ||||||
|         simd::float4 Q; |                 Rect_i32 box = Ri32(group->clip_box); | ||||||
|         simd::float4 R; |                 MTLScissorRect scissor_rect; | ||||||
|         simd::float4 S; |                  | ||||||
|          |                 CGSize frame = [renderer->view drawableSize]; | ||||||
|         P.x = 2.0f * sLength; |                 printf("Drawable Size - w:%f  h:%f\n", frame.width, frame.height); | ||||||
|         P.y = 0.0f; |                  | ||||||
|         P.z = 0.0f; |                 NSUInteger x0 = (NSUInteger)Min(Max(0, box.x0), frame.width - 1); | ||||||
|         P.w = 0.0f; |                 NSUInteger x1 = (NSUInteger)Min(Max(0, box.x1), frame.width); | ||||||
|          |                 NSUInteger y0 = (NSUInteger)Min(Max(0, box.y0), frame.height - 1); | ||||||
|         Q.x = 0.0f; |                 NSUInteger y1 = (NSUInteger)Min(Max(0, box.y1), frame.height); | ||||||
|         Q.y = 2.0f * sHeight; |                  | ||||||
|         Q.z = 0.0f; |                 scissor_rect.x = x0; | ||||||
|         Q.w = 0.0f; |                 scissor_rect.y = y0; | ||||||
|          |                 scissor_rect.width = (x1 - x0); | ||||||
|         R.x = 0.0f; |                 scissor_rect.height = (y1 - y0); | ||||||
|         R.y = 0.0f; |                  | ||||||
|         R.z = sDepth; |                 [render_encoder setScissorRect:scissor_rect]; | ||||||
|         R.w = 0.0f; |             } | ||||||
|          |              | ||||||
|         S.x =  -((right + left) / (right - left)); |             i32 vertex_count = group->vertex_list.vertex_count; | ||||||
|         S.y =  -((top + bottom) / (top - bottom)); |             if (vertex_count > 0){ | ||||||
|         S.z =  -near_depth  * sDepth; |                 // TODO(yuval): Bind a texture | ||||||
|         S.w =  1.0f; |                 { | ||||||
|          |                     Face* face = font_set_face_from_id(font_set, group->face_id); | ||||||
|         simd_float4x4 proj = simd::float4x4(P, Q, R, S); |                     if (face != 0){ | ||||||
|          |                         // TODO(yuval): Bind face texture | ||||||
|         [render_encoder setVertexBytes:&proj |                     } else{ | ||||||
|                 length:sizeof(proj) |                         // TODO(yuval): Bind default texture | ||||||
|                 atIndex:AAPLVertexInputIndexViewportSize]; |                     } | ||||||
| #endif |                 } | ||||||
|          |                  | ||||||
|         // NOTE(yuval): Draw the triangle |                 // NOTE(yuval): Copy the vertex data to the vertex buffer | ||||||
|         [render_encoder drawPrimitives:MTLPrimitiveTypeTriangle |                 { | ||||||
|                 vertexStart:0 |                     u8 *cursor = (u8*)[renderer->buffer contents]; | ||||||
|                 vertexCount:3]; |                     for (Render_Vertex_Array_Node *node = group->vertex_list.first; | ||||||
|  |                          node; | ||||||
|  |                          node = node->next){ | ||||||
|  |                         i32 size = node->vertex_count * sizeof(*node->vertices); | ||||||
|  |                         memcpy(cursor, node->vertices, size); | ||||||
|  |                         cursor += size; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 // NOTE(yuval): Pass the vertex buffer to the vertex shader | ||||||
|  |                 [render_encoder setVertexBuffer:renderer->buffer | ||||||
|  |                         offset:0 | ||||||
|  |                         atIndex:0]; | ||||||
|  |                  | ||||||
|  |                 // NOTE(yuval): Pass the projection matrix to the vertex shader | ||||||
|  |                 [render_encoder setVertexBytes:&proj | ||||||
|  |                         length:sizeof(proj) | ||||||
|  |                         atIndex:1]; | ||||||
|  |                  | ||||||
|  |                 // NOTE(yuval): Draw the vertices | ||||||
|  |                 [render_encoder drawPrimitives:MTLPrimitiveTypeTriangle | ||||||
|  |                         vertexStart:0 | ||||||
|  |                         vertexCount:vertex_count]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|          |          | ||||||
|         [render_encoder endEncoding]; |         [render_encoder endEncoding]; | ||||||
|          |          | ||||||
|  | @ -366,4 +288,6 @@ metal_render(Metal_Renderer *renderer, Render_Target *t){ | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     [command_buffer commit]; |     [command_buffer commit]; | ||||||
|  |      | ||||||
|  |     [renderer->capture_scope endScope]; | ||||||
| } | } | ||||||
|  | @ -12,14 +12,6 @@ Header containing types and enum constants shared between Metal shaders and C/Ob | ||||||
| #include <simd/simd.h> | #include <simd/simd.h> | ||||||
| #define clamp(a,x,b) clamp_((a),(x),(b)) | #define clamp(a,x,b) clamp_((a),(x),(b)) | ||||||
| 
 | 
 | ||||||
| // 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
 | //  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
 | //  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
 | //  the layout of the vertex array in the C code matches the layout that the .metal
 | ||||||
|  |  | ||||||
|  | @ -129,7 +129,7 @@ sd = abs(sd + half_thickness) - half_thickness; | ||||||
| float shape_value = 1.0 - smoothstep(-1.0, 0.0, sd); | float shape_value = 1.0 - smoothstep(-1.0, 0.0, sd); | ||||||
| shape_value *= has_thickness; | shape_value *= has_thickness; | ||||||
| 
 | 
 | ||||||
| out_color = vec4(fragment_color.xyz, fragment_color.a*(sample_value + shape_value)); | out_color = fragment_color;//vec4(fragment_color.xyz, fragment_color.a*(sample_value + shape_value));
 | ||||||
| } | } | ||||||
| )foo"; | )foo"; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -440,7 +440,7 @@ this only gets called for window creation and other extraordinary events. | ||||||
|         [NSApp terminate:nil]; |         [NSApp terminate:nil]; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     // mac_gl_render(&target); |     //mac_gl_render(&target); | ||||||
|     mac_metal_render(&target); |     mac_metal_render(&target); | ||||||
|      |      | ||||||
|     mac_vars.first = false; |     mac_vars.first = false; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Yuval Dolev
						Yuval Dolev