1 module hello_triangle; 2 import metal; 3 4 void print(string str) 5 { 6 NSLog(str.ns); 7 } 8 9 const float[] vertexData = [ 10 0.0, 1.0, 0.0, 11 -1.0, -1.0, 0.0, 12 1.0, -1.0, 0.0 13 ]; 14 15 16 enum metalVertexShader = q{ 17 18 vertex float4 basic_vertex( 19 const device packed_float3* vertex_array [[buffer(0)]], 20 unsigned int vid [[vertex_id]] 21 ) 22 { 23 return float4(vertex_array[vid], 1.0); 24 } 25 26 }; 27 28 enum metalFragmentShader = q{ 29 30 fragment half4 basic_fragment() 31 { 32 return half4(1.0); 33 } 34 35 }; 36 37 38 import metal; 39 40 __gshared MTLBuffer vertexBuffer; 41 __gshared MTLRenderPipelineDescriptor pipelineDescriptor; 42 __gshared MTLCommandQueue commandQueue; 43 __gshared MTLRenderPipelineState state; 44 45 enum DefaultPixelFormat = MTLPixelFormat.BGRA8Unorm_sRGB; 46 47 extern(C) void initMetal(MTLDevice device) 48 { 49 import std.conv:to; 50 print("Initializing Metal!"); 51 vertexBuffer = device.newBuffer(vertexData.ptr, float.sizeof*vertexData.length, MTLResourceOptions.DefaultCache); 52 53 NSError err; 54 MTLLibrary defaultLibrary = device.newLibraryWithSource((metalVertexShader ~ metalFragmentShader).ns, null, &err); 55 if(err !is null || defaultLibrary is null) 56 { 57 NSLog("Error compiling shader %@".ns, err); 58 return; 59 } 60 61 print("Getting vertex and fragment shaders"); 62 MTLFunction fragmentProgram = defaultLibrary.newFunctionWithName("basic_fragment".ns); 63 MTLFunction vertexProgram = defaultLibrary.newFunctionWithName("basic_vertex".ns); 64 65 if(fragmentProgram is null) 66 print("Could not get fragment shader"); 67 if(vertexProgram is null) 68 print("Coult not get vertex shader"); 69 70 print("Creating VertexFormat"); 71 72 MTLVertexDescriptor descriptor = MTLVertexDescriptor.vertexDescriptor; 73 74 enum POSITION = 0; 75 enum BufferIndexMeshPositions = 0; 76 descriptor.attributes[POSITION].format = MTLVertexFormat.float3; 77 descriptor.attributes[POSITION].offset = 0; 78 descriptor.attributes[POSITION].bufferIndex = BufferIndexMeshPositions; 79 80 descriptor.layouts[POSITION].stepRate = 1; 81 descriptor.layouts[POSITION].stepFunction = MTLVertexStepFunction.PerVertex; 82 descriptor.layouts[POSITION].stride = float.sizeof*3; 83 84 85 print("Creating PipelineDescriptor"); 86 pipelineDescriptor = MTLRenderPipelineDescriptor.alloc.initialize; 87 pipelineDescriptor.label = "TestProgram".ns; 88 pipelineDescriptor.vertexFunction = vertexProgram; 89 pipelineDescriptor.fragmentFunction = fragmentProgram; 90 pipelineDescriptor.vertexDescriptor = descriptor; 91 pipelineDescriptor.colorAttachments[0].pixelFormat = DefaultPixelFormat; 92 pipelineDescriptor.depthAttachmentPixelFormat = MTLPixelFormat.Depth32Float_Stencil8; 93 pipelineDescriptor.stencilAttachmentPixelFormat = MTLPixelFormat.Depth32Float_Stencil8; 94 95 state = device.newRenderPipelineStateWithDescriptor(pipelineDescriptor, &err); 96 97 if(state is null || err !is null) 98 { 99 NSLog("Failed to create RenderPipelineDescriptor %@".ns, err); 100 return; 101 } 102 103 104 commandQueue = device.newCommandQueue(); 105 106 } 107 108 extern(C) void renderMetal(MTKView view) 109 { 110 MTLRenderPassDescriptor desc = view.currentRenderPassDescriptor; 111 if(desc is null) return; 112 113 MTLCommandBuffer cmdBuffer = commandQueue.commandBuffer(); 114 cmdBuffer.label = "MyCommand".ns; 115 116 117 MTLRenderCommandEncoder encoder = cmdBuffer.renderCommandEncoderWithDescriptor(desc); 118 119 encoder.setRenderPipelineState(state); 120 encoder.setVertexBuffer(vertexBuffer, 0, 0); 121 122 encoder.drawPrimitives(MTLPrimitiveType.Triangle, 0, 9); 123 124 encoder.endEncoding(); 125 cmdBuffer.presentDrawable(view.currentDrawable); 126 cmdBuffer.commit(); 127 128 // desc.colorAttachments[0].texture = 129 }