1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-12 15:31:09 +00:00

Having learnt a bit more: eliminates Metal attribute tags, switches to more natural expression of structs.

Also thereby eliminates the need for a forced alignas(4) on various structs.
This commit is contained in:
Thomas Harte 2020-08-08 17:27:32 -04:00
parent edf41b06fd
commit bdcf266e45
3 changed files with 40 additions and 30 deletions

View File

@ -12,31 +12,43 @@ using namespace metal;
struct Uniforms { struct Uniforms {
// This is used to scale scan positions, i.e. it provides the range // This is used to scale scan positions, i.e. it provides the range
// for mapping from scan-style integer positions into eye space. // for mapping from scan-style integer positions into eye space.
int2 scale [[attribute(0)]]; int2 scale;
// This provides the intended height of a scan, in eye-coordinate terms. // This provides the intended height of a scan, in eye-coordinate terms.
float lineWidth [[attribute(1)]]; float lineWidth;
// Provides a scaling factor in order to preserve 4:3 central content. // Provides a scaling factor in order to preserve 4:3 central content.
float aspectRatioMultiplier [[attribute(2)]]; float aspectRatioMultiplier;
}; };
// This is intended to match `Scan` as defined by the BufferingScanTarget. // This is intended to match the net effect of `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 { struct Scan {
uint32_t startPosition [[attribute(0)]]; struct EndPoint {
uint32_t startOffsetAndAngle [[attribute(1)]]; uint16_t position[2];
uint32_t startCycles [[attribute(2)]]; uint16_t dataOffset;
uint16_t compositeAngle;
uint16_t cyclesSinceRetrace;
} endPoints[2];
uint32_t endPosition [[attribute(3)]]; uint8_t compositeAmplitude;
uint32_t endOffsetAndAngle [[attribute(4)]]; uint16_t dataY;
uint32_t endCycles [[attribute(5)]]; uint16_t line;
uint32_t compositeAmplitude [[attribute(6)]];
uint32_t dataYAndLine [[attribute(7)]];
}; };
// This matches the BufferingScanTarget's `Line`.
struct Line {
struct EndPoint {
uint16_t position[2];
uint16_t cyclesSinceRetrace;
uint16_t compositeAngle;
} endPoints[2];
uint16_t line;
uint8_t compositeAmplitude;
};
// This is an intermediate struct, which is TEMPORARY.
struct ColouredVertex { struct ColouredVertex {
float4 position [[position]]; float4 position [[position]];
}; };
@ -48,21 +60,21 @@ vertex ColouredVertex scanVertexMain( constant Uniforms &uniforms [[buffer(1)]],
constant Scan *scans [[buffer(0)]], constant Scan *scans [[buffer(0)]],
uint instanceID [[instance_id]], uint instanceID [[instance_id]],
uint vertexID [[vertex_id]]) { uint vertexID [[vertex_id]]) {
// Unpack start and end vertices; little-endian numbers are assumed here. // Get start and end vertices in regular float2 form.
const float2 start = float2( const float2 start = float2(
float(scans[instanceID].startPosition & 0xffff) / float(uniforms.scale.x), float(scans[instanceID].endPoints[0].position[0]) / float(uniforms.scale.x),
float(scans[instanceID].startPosition >> 16) / float(uniforms.scale.y) float(scans[instanceID].endPoints[0].position[1]) / float(uniforms.scale.y)
); );
const float2 end = float2( const float2 end = float2(
float(scans[instanceID].endPosition & 0xffff) / float(uniforms.scale.x), float(scans[instanceID].endPoints[1].position[0]) / float(uniforms.scale.x),
float(scans[instanceID].endPosition >> 16) / float(uniforms.scale.y) float(scans[instanceID].endPoints[1].position[1]) / float(uniforms.scale.y)
); );
// Calculate the tangent and normal. // Calculate the tangent and normal.
const float2 tangent = (end - start); const float2 tangent = (end - start);
const float2 normal = float2(-tangent.y, tangent.x) / length(tangent); const float2 normal = float2(-tangent.y, tangent.x) / length(tangent);
// Hence determine this quad's real shape. // Hence determine this quad's real shape, using vertexID to pick a corner.
ColouredVertex output; ColouredVertex output;
output.position = float4( output.position = float4(
((start + (float(vertexID&2) * 0.5) * tangent + (float(vertexID&1) - 0.5) * normal * uniforms.lineWidth) * float2(2.0, -2.0) + float2(-1.0, 1.0)) * float2(uniforms.aspectRatioMultiplier, 1.0), ((start + (float(vertexID&2) * 0.5) * tangent + (float(vertexID&1) - 0.5) * normal * uniforms.lineWidth) * float2(2.0, -2.0) + float2(-1.0, 1.0)) * float2(uniforms.aspectRatioMultiplier, 1.0),
@ -72,6 +84,6 @@ vertex ColouredVertex scanVertexMain( constant Uniforms &uniforms [[buffer(1)]],
return output; return output;
} }
fragment float4 scanFragmentMain(ColouredVertex vert [[stage_in]]) { fragment half4 scanFragmentMain(ColouredVertex vert [[stage_in]]) {
return float4(1.0); return half4(1.0);
} }

View File

@ -210,11 +210,9 @@ struct ScanTarget {
/*! /*!
Defines a scan in terms of its two endpoints. Defines a scan in terms of its two endpoints.
Is guaranteed to be a multiple of four bytes in size.
*/ */
struct alignas(4) Scan { struct Scan {
struct alignas(4) EndPoint { struct EndPoint {
/// Provide the coordinate of this endpoint. These are fixed point, purely fractional /// Provide the coordinate of this endpoint. These are fixed point, purely fractional
/// numbers, relative to the scale provided in the Modals. /// numbers, relative to the scale provided in the Modals.
uint16_t x, y; uint16_t x, y;

View File

@ -50,7 +50,7 @@ class BufferingScanTarget: public Outputs::Display::ScanTarget {
// Extends the definition of a Scan to include two extra fields, // Extends the definition of a Scan to include two extra fields,
// completing this scan's source data and destination locations. // completing this scan's source data and destination locations.
struct alignas(4) Scan { struct Scan {
Outputs::Display::ScanTarget::Scan scan; Outputs::Display::ScanTarget::Scan scan;
/// Stores the y coordinate for this scan's data within the write area texture. /// Stores the y coordinate for this scan's data within the write area texture.
@ -65,8 +65,8 @@ class BufferingScanTarget: public Outputs::Display::ScanTarget {
/// Defines the boundaries of a complete line of video — a 2d start and end location, /// Defines the boundaries of a complete line of video — a 2d start and end location,
/// composite phase and amplitude (if relevant), the source line in the intermediate buffer /// composite phase and amplitude (if relevant), the source line in the intermediate buffer
/// plus the start and end offsets of the area that is visible from the intermediate buffer. /// plus the start and end offsets of the area that is visible from the intermediate buffer.
struct alignas(4) Line { struct Line {
struct alignas(4) EndPoint { struct EndPoint {
uint16_t x, y; uint16_t x, y;
uint16_t cycles_since_end_of_horizontal_retrace; uint16_t cycles_since_end_of_horizontal_retrace;
int16_t composite_angle; int16_t composite_angle;