1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-23 03:32:32 +00:00

Gets some uniforms in on the action.

With some effort towards scans, but incompletely so.
This commit is contained in:
Thomas Harte 2020-08-07 21:19:17 -04:00
parent 4c9418f59a
commit 4421acef34
2 changed files with 75 additions and 35 deletions

View File

@ -10,16 +10,26 @@
#import <Metal/Metal.h> #import <Metal/Metal.h>
namespace {
struct Uniforms {
int32_t scale[2];
float lineWidth;
};
}
@implementation CSScanTarget { @implementation CSScanTarget {
id<MTLCommandQueue> _commandQueue; id<MTLCommandQueue> _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<MTLFunction> _vertexShader; id<MTLFunction> _vertexShader;
id<MTLFunction> _fragmentShader; id<MTLFunction> _fragmentShader;
id<MTLBuffer> _verticesBuffer;
id<MTLRenderPipelineState> _gouraudPipeline; id<MTLRenderPipelineState> _gouraudPipeline;
// Buffers.
id<MTLBuffer> _quadBuffer; // i.e. four vertices defining a quad.
id<MTLBuffer> _uniformsBuffer;
id<MTLBuffer> _scansBuffer;
} }
- (nonnull instancetype)initWithView:(nonnull MTKView *)view { - (nonnull instancetype)initWithView:(nonnull MTKView *)view {
@ -27,42 +37,35 @@
if(self) { if(self) {
_commandQueue = [view.device newCommandQueue]; _commandQueue = [view.device newCommandQueue];
// Generate some static buffers. AS A TEST. // Install the standard quad.
constexpr float vertices[] = { constexpr float vertices[] = {
-0.9f, -0.9f, // Position. -0.9f, -0.9f,
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.9f, -0.9f,
0.0f, 0.0f, 1.0f,
0.9f, 0.9f, 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]; MTLVertexDescriptor *vertexDescriptor = [[MTLVertexDescriptor alloc] init];
// Position.
vertexDescriptor.attributes[0].bufferIndex = 0; vertexDescriptor.attributes[0].bufferIndex = 0;
vertexDescriptor.attributes[0].offset = 0; vertexDescriptor.attributes[0].offset = 0;
vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2;
vertexDescriptor.layouts[0].stride = sizeof(float)*2;
// 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;
// Generate TEST pipeline. // Generate TEST pipeline.
id<MTLLibrary> library = [view.device newDefaultLibrary]; id<MTLLibrary> library = [view.device newDefaultLibrary];
MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
pipelineDescriptor.vertexFunction = [library newFunctionWithName:@"vertex_main"]; pipelineDescriptor.vertexFunction = [library newFunctionWithName:@"scanVertexMain"];
pipelineDescriptor.fragmentFunction = [library newFunctionWithName:@"fragment_main"]; pipelineDescriptor.fragmentFunction = [library newFunctionWithName:@"scanFragmentMain"];
pipelineDescriptor.colorAttachments[0].pixelFormat = view.colorPixelFormat; pipelineDescriptor.colorAttachments[0].pixelFormat = view.colorPixelFormat;
pipelineDescriptor.vertexDescriptor = vertexDescriptor; pipelineDescriptor.vertexDescriptor = vertexDescriptor;
_gouraudPipeline = [view.device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:nil]; _gouraudPipeline = [view.device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:nil];
@ -70,6 +73,11 @@
return self; return self;
} }
- (void)setUniforms:(const Uniforms &)uniforms {
memcpy(_uniformsBuffer.contents, &uniforms, sizeof(Uniforms));
// [_uniformsBuffer didModifyRange:NSMakeRange(0, sizeof(Uniforms))];
}
/*! /*!
@method mtkView:drawableSizeWillChange: @method mtkView:drawableSizeWillChange:
@abstract Called whenever the drawableSize of the view will change @abstract Called whenever the drawableSize of the view will change
@ -95,7 +103,10 @@
// Drawing. Just the test triangle, as described above. // Drawing. Just the test triangle, as described above.
[encoder setRenderPipelineState:_gouraudPipeline]; [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]; [encoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4 instanceCount:1];
// Complete encoding. // Complete encoding.

View File

@ -12,23 +12,52 @@ using namespace metal;
// These two structs are the same, but defined separately as an artefact // 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. // 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)]]; float2 position [[attribute(0)]];
float3 colour [[attribute(1)]];
}; };
struct ColouredVertex { struct ColouredVertex {
float4 position [[position]]; 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; ColouredVertex output;
output.position = float4(vert.position, 0.0, 1.0); output.position = float4(vert.position * uniforms.lineWidth, 0.0, 1.0);
output.colour = float4(vert.colour, 1.0);
return output; return output;
} }
fragment float4 fragment_main(ColouredVertex vert [[stage_in]]) { fragment float4 scanFragmentMain(ColouredVertex vert [[stage_in]]) {
return vert.colour; return float4(1.0);
} }