From 4421acef34d8acae159ee4a2b3dddc0a0f89718d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 7 Aug 2020 21:19:17 -0400 Subject: [PATCH] Gets some uniforms in on the action. With some effort towards scans, but incompletely so. --- .../Clock Signal/ScanTarget/CSScanTarget.mm | 65 +++++++++++-------- .../Clock Signal/ScanTarget/ScanTarget.metal | 45 ++++++++++--- 2 files changed, 75 insertions(+), 35 deletions(-) diff --git a/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm b/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm index 98e094260..533f58c0b 100644 --- a/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm +++ b/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm @@ -10,16 +10,26 @@ #import +namespace { + +struct Uniforms { + int32_t scale[2]; + float lineWidth; +}; + +} + @implementation CSScanTarget { id _commandQueue; - // TEST ONLY: to check that I'm drawing _something_, I'm heading towards ye standard - // Gouraud shading triangle. https://metalbyexample.com/up-and-running-2/ is providing - // much of the inspiration, albeit that I'm proceeding via MKLView. id _vertexShader; id _fragmentShader; - id _verticesBuffer; id _gouraudPipeline; + + // Buffers. + id _quadBuffer; // i.e. four vertices defining a quad. + id _uniformsBuffer; + id _scansBuffer; } - (nonnull instancetype)initWithView:(nonnull MTKView *)view { @@ -27,42 +37,35 @@ if(self) { _commandQueue = [view.device newCommandQueue]; - // Generate some static buffers. AS A TEST. + // Install the standard quad. constexpr float vertices[] = { - -0.9f, -0.9f, // Position. - 1.0f, 0.0f, 0.0f, // Colour. - + -0.9f, -0.9f, -0.9f, 0.9f, - 0.0f, 1.0f, 0.0f, - 0.9f, -0.9f, - 0.0f, 0.0f, 1.0f, - 0.9f, 0.9f, - 0.0f, 1.0f, 1.0f, }; - _verticesBuffer = [view.device newBufferWithBytes:vertices length:sizeof(vertices) options:MTLResourceOptionCPUCacheModeDefault]; + _quadBuffer = [view.device newBufferWithBytes:vertices length:sizeof(vertices) options:MTLResourceCPUCacheModeDefaultCache]; + // Allocate space for uniforms. + _uniformsBuffer = [view.device newBufferWithLength:16 options:MTLResourceCPUCacheModeWriteCombined]; + Uniforms testUniforms = { + .scale = {0, 0}, + .lineWidth = 0.1f + }; + [self setUniforms:testUniforms]; + + // The quad buffer has only 2d positions. MTLVertexDescriptor *vertexDescriptor = [[MTLVertexDescriptor alloc] init]; - - // Position. vertexDescriptor.attributes[0].bufferIndex = 0; vertexDescriptor.attributes[0].offset = 0; vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; - - // Colour. - vertexDescriptor.attributes[1].bufferIndex = 0; - vertexDescriptor.attributes[1].offset = sizeof(float)*2; - vertexDescriptor.attributes[1].format = MTLVertexFormatFloat3; - - // Total vertex size. - vertexDescriptor.layouts[0].stride = sizeof(float)*5; + vertexDescriptor.layouts[0].stride = sizeof(float)*2; // Generate TEST pipeline. id library = [view.device newDefaultLibrary]; MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; - pipelineDescriptor.vertexFunction = [library newFunctionWithName:@"vertex_main"]; - pipelineDescriptor.fragmentFunction = [library newFunctionWithName:@"fragment_main"]; + pipelineDescriptor.vertexFunction = [library newFunctionWithName:@"scanVertexMain"]; + pipelineDescriptor.fragmentFunction = [library newFunctionWithName:@"scanFragmentMain"]; pipelineDescriptor.colorAttachments[0].pixelFormat = view.colorPixelFormat; pipelineDescriptor.vertexDescriptor = vertexDescriptor; _gouraudPipeline = [view.device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:nil]; @@ -70,6 +73,11 @@ return self; } +- (void)setUniforms:(const Uniforms &)uniforms { + memcpy(_uniformsBuffer.contents, &uniforms, sizeof(Uniforms)); +// [_uniformsBuffer didModifyRange:NSMakeRange(0, sizeof(Uniforms))]; +} + /*! @method mtkView:drawableSizeWillChange: @abstract Called whenever the drawableSize of the view will change @@ -95,7 +103,10 @@ // Drawing. Just the test triangle, as described above. [encoder setRenderPipelineState:_gouraudPipeline]; - [encoder setVertexBuffer:_verticesBuffer offset:0 atIndex:0]; + + [encoder setVertexBuffer:_quadBuffer offset:0 atIndex:0]; + [encoder setVertexBuffer:_uniformsBuffer offset:0 atIndex:1]; + [encoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4 instanceCount:1]; // Complete encoding. diff --git a/OSBindings/Mac/Clock Signal/ScanTarget/ScanTarget.metal b/OSBindings/Mac/Clock Signal/ScanTarget/ScanTarget.metal index 7e2a9822e..e95180d9c 100644 --- a/OSBindings/Mac/Clock Signal/ScanTarget/ScanTarget.metal +++ b/OSBindings/Mac/Clock Signal/ScanTarget/ScanTarget.metal @@ -12,23 +12,52 @@ using namespace metal; // These two structs are the same, but defined separately as an artefact // of my learning process, and the fact that they soon won't be. -struct InputVertex { +struct Uniforms { + // This is used to scale scan positions, i.e. it provides the range + // for mapping from scan-style integer positions into eye space. + int2 scale [[attribute(0)]]; + + // This provides the intended width of a scan, in eye-coordinate terms. + float lineWidth [[attribute(1)]]; +}; + +// This is intended to match `Scan` as defined by the BufferingScanTarget. +// Fields have been combined as necessary to make them all at least four +// bytes in size, since that is the required attribute alignment in Swift. +struct Scan { + uint32_t startPosition [[attribute(0)]]; + uint32_t startOffsetAndAngle [[attribute(1)]]; + uint32_t startCycles [[attribute(2)]]; + + uint32_t endPosition [[attribute(3)]]; + uint32_t endOffsetAndAngle [[attribute(4)]]; + uint32_t endCycles [[attribute(5)]]; + + uint32_t compositeAmplitude [[attribute(6)]]; + uint32_t dataYAndLine [[attribute(7)]]; +}; + +// This is a custom thing defining one corner of a quad. +struct QuadInputVertex { float2 position [[attribute(0)]]; - float3 colour [[attribute(1)]]; }; struct ColouredVertex { float4 position [[position]]; - float4 colour; }; -vertex ColouredVertex vertex_main(InputVertex vert [[stage_in]]) { + +// MARK: - Scan shaders; these do final output to the display. + +vertex ColouredVertex scanVertexMain( QuadInputVertex vert [[stage_in]], + constant Uniforms &uniforms [[buffer(1)]], + constant Scan *scans [[buffer(2)]], + ushort instance [[instance_id]]) { ColouredVertex output; - output.position = float4(vert.position, 0.0, 1.0); - output.colour = float4(vert.colour, 1.0); + output.position = float4(vert.position * uniforms.lineWidth, 0.0, 1.0); return output; } -fragment float4 fragment_main(ColouredVertex vert [[stage_in]]) { - return vert.colour; +fragment float4 scanFragmentMain(ColouredVertex vert [[stage_in]]) { + return float4(1.0); }