Help us shape the future of Go! Take the 2026 Go Developer Survey

msl

package
v0.21.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 5 Imported by: 2

Documentation

Overview

Package msl implements Metal Shading Language (MSL) code generation for naga.

MSL is Apple's shader language for the Metal graphics API. It is based on C++14 with extensions for GPU programming, including explicit address spaces, attribute-based parameter binding, and a metal:: namespace for standard library functions.

Usage

To compile a WGSL shader to MSL:

module, err := wgsl.Parse(source)
if err != nil {
    return err
}

options := msl.Options{
    LangVersion: msl.Version{Major: 2, Minor: 1},
}

mslCode, err := msl.Compile(module, options)
if err != nil {
    return err
}

MSL Language Versions

Options.LangVersion is the version the output is written for (zero: 2.1). The backend never raises it: a shader that needs a newer MSL is refused with a *backend.VersionError, as Rust naga refuses it. The versions some features need:

  • MSL 1.2: @builtin(instance_index), @blend_src, reverseBits, extractBits, insertBits, writable storage buffers in fragment shaders, writable storage textures in vertex and fragment shaders, read-write storage textures
  • MSL 2.0: binding arrays of samplers, textures and read-only or write-only storage textures
  • MSL 2.1: @invariant
  • MSL 2.2: @builtin(view_index)
  • MSL 2.3: @builtin(primitive_index), @builtin(barycentric)
  • MSL 2.4: ray queries
  • MSL 3.0: binding arrays of read-write storage textures, mesh shaders
  • MSL 3.1: 64-bit storage textures (r64uint, r64sint)
  • MSL 4.0: @interpolate(per_vertex)

Type Mapping

WGSL types map to MSL as follows:

WGSL           MSL
----           ---
bool           bool
i32            int
u32            uint
f32            float
f16            half
vec2<T>        metal::T2
vec3<T>        metal::T3
vec4<T>        metal::T4
mat4x4<f32>    metal::float4x4
array<T, N>    array<T, N>  (wrapped in struct)
texture_2d     metal::texture2d<float>
sampler        metal::sampler

Address Spaces

WGSL address spaces map to MSL as:

uniform    -> constant
storage    -> device
private    -> thread
workgroup  -> threadgroup
function   -> thread (stack)

Entry Points

Entry points are generated with appropriate stage keywords:

  • vertex: Vertex shaders with [[stage_in]], [[vertex_id]], etc.
  • fragment: Fragment shaders with [[position]], [[color(N)]], etc.
  • kernel: Compute shaders with [[thread_position_in_grid]], etc.

Helper Functions

Some WGSL operations require polyfill functions in MSL:

  • naga_div: Safe integer division (typed overloads, handles zero and INT_MIN/-1)
  • naga_mod: Safe integer modulo (typed overloads, handles zero and INT_MIN/-1)
  • naga_modf: modf with WGSL-compatible result struct
  • naga_frexp: frexp with WGSL-compatible result struct
  • _mslBufferSizes: Struct for runtime-sized array buffer sizes

Concurrency

Every exported function is safe for concurrent use. Compile never modifies its input module, so one module can be compiled for several targets at once.

Index

Constants

This section is empty.

Variables

View Source
var (
	Version1_0 = Version{Major: 1, Minor: 0}
	Version1_2 = Version{Major: 1, Minor: 2}
	Version2_0 = Version{Major: 2, Minor: 0}
	Version2_1 = Version{Major: 2, Minor: 1}
	Version2_3 = Version{Major: 2, Minor: 3}
	Version2_4 = Version{Major: 2, Minor: 4}
	Version3_0 = Version{Major: 3, Minor: 0}
	Version3_1 = Version{Major: 3, Minor: 1}
)

Common MSL versions.

Functions

This section is empty.

Types

type AttributeMapping added in v0.15.0

type AttributeMapping struct {
	ShaderLocation uint32
	Offset         uint32
	Format         VertexFormat
}

AttributeMapping maps a vertex attribute to a shader location.

type BindExternalTextureTarget added in v0.15.0

type BindExternalTextureTarget struct {
	Planes [3]uint8
	Params uint8
}

BindExternalTextureTarget specifies the Metal binding slots for an external texture global variable. External textures are lowered to 3 texture planes and a constant buffer of NagaExternalTextureParams.

type BindSamplerTarget added in v0.15.0

type BindSamplerTarget struct {
	// IsInline indicates the sampler is an inline (constexpr) sampler.
	IsInline bool
	// Slot is the binding slot (for resource samplers) or index into
	// Options.InlineSamplers (for inline samplers).
	Slot uint8
}

BindSamplerTarget specifies how a sampler is bound.

type BindTarget

type BindTarget struct {
	// Buffer is the buffer binding slot. Nil if not bound as buffer.
	Buffer *uint8

	// Texture is the texture binding slot. Nil if not bound as texture.
	Texture *uint8

	// Sampler is the sampler binding slot. Nil if not bound as sampler.
	Sampler *BindSamplerTarget

	// ExternalTexture is the binding for external texture planes + params.
	ExternalTexture *BindExternalTextureTarget

	// Mutable indicates if this is a read-write resource.
	Mutable bool
}

BindTarget specifies the Metal binding slots for a resource.

type EntryPointResources

type EntryPointResources struct {
	// Resources maps (group, binding) pairs to Metal bind targets.
	Resources map[ir.ResourceBinding]BindTarget

	// SizesBuffer is the buffer slot for runtime array sizes.
	// Required when using runtime-sized arrays.
	SizesBuffer *uint8

	// ImmediatesBuffer is the buffer slot for immediate data.
	// Nil if immediate data is not used.
	ImmediatesBuffer *uint8
}

EntryPointResources maps WGSL resource bindings to Metal binding slots.

type InlineSampler added in v0.15.0

type InlineSampler struct {
	Coord       SamplerCoord
	Address     [3]SamplerAddress
	BorderColor SamplerBorderColor
	MagFilter   SamplerFilter
	MinFilter   SamplerFilter
	MipFilter   *SamplerFilter // nil if not set
	CompareFunc SamplerCompareFunc
}

InlineSampler defines an inline (constexpr) sampler in Metal.

type Options

type Options struct {
	// LangVersion is the MSL version written in the header and the
	// highest one the output may use; the zero value is 2.1 (Rust naga's
	// default is 1.0). The backend never raises it: a feature of a newer
	// MSL is an error, a *backend.VersionError in backend.VersionMSL that
	// names the feature and the version it needs, as Rust naga refuses it.
	// Pass the device's highest supported version.
	LangVersion Version

	// PerEntryPointMap maps entry point names to their resource bindings.
	// If nil, bindings are auto-generated: the module's resource globals,
	// sorted by (group, binding), get consecutive buffer, texture and sampler
	// slots. These slots depend on which globals the module has, so
	// naga.ProcessOverrides with an EntryPoint, which removes unused globals,
	// can move them. Pass a map for stable slots (Rust naga requires one).
	// A non-nil map, empty too, must give every resource an entry point uses
	// a slot of its kind in that entry point's entry, and the sizes and
	// immediates buffers it needs; an entry point without an entry has none.
	// Otherwise Compile fails with an error wrapping
	// backend.ErrMissingBinding, unless FakeMissingBindings is set.
	PerEntryPointMap map[string]EntryPointResources

	// InlineSamplers defines constexpr samplers to be inlined into the code.
	// Referenced by BindSamplerTarget.Slot when IsInline is true.
	InlineSamplers []InlineSampler

	// BoundsCheckPolicies selects how out-of-bounds indices and image loads
	// are handled. The zero value is backend.BoundsCheckRestrict everywhere,
	// which WebGPU requires; Rust naga's default is Unchecked, and wgpu-hal's
	// Metal backend passes Restrict for Index, Buffer and ImageLoad (Unchecked
	// when its runtime bounds checks are off) and Unchecked for BindingArray.
	// Every field honors every policy, as Rust naga's MSL writer does:
	// Restrict with metal::min on the index (a runtime-sized array takes its
	// length from the sizes buffer) and on image coordinates,
	// ReadZeroSkipWrite with a ternary or an if around the access,
	// Unchecked with no code.
	BoundsCheckPolicies backend.BoundsCheckPolicies

	// ZeroInitializeWorkgroupMemory is how compute entry points zero the
	// threadgroup variables they use, as WebGPU requires. The zero value,
	// backend.ZeroInitWorkgroupPolyfill, stores zero to them from the first
	// invocation and adds a threadgroup barrier, as Rust naga's default
	// zero_initialize_workgroup_memory: true does. ZeroInitWorkgroupNone
	// leaves them as they are; ZeroInitWorkgroupNative is an error, Metal
	// has no way to ask for it.
	ZeroInitializeWorkgroupMemory backend.ZeroInitializeWorkgroupMemoryMode

	// SkipLoopBounding leaves loops as they are. By default every loop gets
	// a decrementing 64-bit counter that breaks out of it, so an infinite
	// loop, undefined behavior that can hang the device, ends. Rust naga's
	// force_loop_bounding defaults to true, and wgpu-hal passes true.
	SkipLoopBounding bool

	// FakeMissingBindings writes a placeholder attribute, [[user(fake0)]],
	// for a resource a non-nil PerEntryPointMap gives no slot, instead of
	// failing. Rust naga's fake_missing_bindings defaults to true; wgpu-hal
	// passes false, the zero value here.
	FakeMissingBindings bool

	// EntryPoint selects the one entry point to write, as Rust naga's
	// msl::PipelineOptions::entry_point; nil writes every entry point. One
	// the module does not have is an error wrapping
	// backend.ErrEntryPointNotFound.
	EntryPoint *backend.EntryPointSelector

	// AllowAndForcePointSize forces point size output for vertex shaders.
	AllowAndForcePointSize bool

	// VertexPulling, when set, makes vertex entry points read their inputs
	// from vertex buffers instead of stage_in (Rust naga's
	// vertex_pulling_transform with its vertex_buffer_mappings).
	VertexPulling *VertexPullingOptions

	// ClampFragDepth, when set, clamps the depth a fragment entry point
	// writes to the range in two f32, min then max, at byte offset
	// ClampFragDepth.Offset of the entry point's immediates buffer
	// (EntryPointResources.ImmediatesBuffer), which it then needs. WebGPU
	// clamps frag_depth to the viewport's depth range; the caller puts the
	// viewport's minDepth and maxDepth there, where Dawn's ClampFragDepth
	// transform reads them on Metal, and as the spirv option of the same
	// name reads them from push constants. An entry point with immediate
	// data of its own finds the range in the same buffer, so Offset has to
	// be past that data. Rust naga has no such option.
	ClampFragDepth *backend.ClampFragDepth

	// FixedSampleMask, when set, is the render pipeline's sample mask, which
	// a fragment entry point applies itself: it ANDs it into the sample_mask
	// it returns, or returns it as a [[sample_mask]] output when it returns
	// none. Metal has no pipeline sample mask; Dawn folds it into the shader
	// the same way. Leave it nil for a mask of all ones. Rust naga has no
	// such option.
	FixedSampleMask *uint32
}

Options configures MSL code generation.

func DefaultOptions

func DefaultOptions() Options

DefaultOptions returns the zero Options, the safe defaults: MSL 2.1, Restrict bounds checks, bounded loops.

type SamplerAddress added in v0.15.0

type SamplerAddress int

SamplerAddress specifies the addressing mode for an inline sampler.

const (
	SamplerAddressRepeat SamplerAddress = iota
	SamplerAddressMirroredRepeat
	SamplerAddressClampToEdge
	SamplerAddressClampToZero
	SamplerAddressClampToBorder
)

type SamplerBorderColor added in v0.15.0

type SamplerBorderColor int

SamplerBorderColor specifies the border color for an inline sampler.

const (
	SamplerBorderColorTransparentBlack SamplerBorderColor = iota
	SamplerBorderColorOpaqueBlack
	SamplerBorderColorOpaqueWhite
)

type SamplerCompareFunc added in v0.15.0

type SamplerCompareFunc int

SamplerCompareFunc specifies the comparison function for an inline sampler.

const (
	SamplerCompareFuncNever SamplerCompareFunc = iota
	SamplerCompareFuncLess
	SamplerCompareFuncLessEqual
	SamplerCompareFuncGreater
	SamplerCompareFuncGreaterEqual
	SamplerCompareFuncEqual
	SamplerCompareFuncNotEqual
	SamplerCompareFuncAlways
)

type SamplerCoord added in v0.15.0

type SamplerCoord int

SamplerCoord specifies the coordinate system for an inline sampler.

const (
	SamplerCoordNormalized SamplerCoord = iota
	SamplerCoordPixel
)

type SamplerFilter added in v0.15.0

type SamplerFilter int

SamplerFilter specifies the filtering mode for an inline sampler.

const (
	SamplerFilterNearest SamplerFilter = iota
	SamplerFilterLinear
)

type TranslationInfo

type TranslationInfo struct {
	// EntryPointNames maps original entry point names to generated MSL names.
	EntryPointNames map[string]string

	// RequiresSizesBuffer indicates if a sizes buffer is needed for
	// runtime-sized arrays.
	RequiresSizesBuffer bool
}

TranslationInfo contains information about the compiled MSL output.

func Compile

func Compile(module *ir.Module, options Options) (string, TranslationInfo, error)

Compile generates MSL source code from an IR module. Returns the MSL source as a string and translation info, or an error.

type Version

type Version struct {
	Major uint8
	Minor uint8
}

Version represents an MSL language version.

func (Version) Less added in v0.15.0

func (v Version) Less(other Version) bool

Less returns true if v is strictly less than other.

func (Version) String

func (v Version) String() string

String returns the version as "major.minor".

type VertexBufferMapping added in v0.15.0

type VertexBufferMapping struct {
	ID         uint32
	Stride     uint32
	StepMode   VertexBufferStepMode
	Attributes []AttributeMapping
}

VertexBufferMapping describes a vertex buffer and its attributes.

type VertexBufferStepMode added in v0.15.0

type VertexBufferStepMode int

VertexBufferStepMode defines how to advance the data in vertex buffers.

const (
	VertexStepModeConstant   VertexBufferStepMode = 0
	VertexStepModeByVertex   VertexBufferStepMode = 1
	VertexStepModeByInstance VertexBufferStepMode = 2
)

type VertexFormat added in v0.15.0

type VertexFormat int

VertexFormat describes the format of a vertex attribute.

const (
	VertexFormatUint8           VertexFormat = 0
	VertexFormatUint8x2         VertexFormat = 1
	VertexFormatUint8x4         VertexFormat = 2
	VertexFormatSint8           VertexFormat = 3
	VertexFormatSint8x2         VertexFormat = 4
	VertexFormatSint8x4         VertexFormat = 5
	VertexFormatUnorm8          VertexFormat = 6
	VertexFormatUnorm8x2        VertexFormat = 7
	VertexFormatUnorm8x4        VertexFormat = 8
	VertexFormatSnorm8          VertexFormat = 9
	VertexFormatSnorm8x2        VertexFormat = 10
	VertexFormatSnorm8x4        VertexFormat = 11
	VertexFormatUint16          VertexFormat = 12
	VertexFormatUint16x2        VertexFormat = 13
	VertexFormatUint16x4        VertexFormat = 14
	VertexFormatSint16          VertexFormat = 15
	VertexFormatSint16x2        VertexFormat = 16
	VertexFormatSint16x4        VertexFormat = 17
	VertexFormatUnorm16         VertexFormat = 18
	VertexFormatUnorm16x2       VertexFormat = 19
	VertexFormatUnorm16x4       VertexFormat = 20
	VertexFormatSnorm16         VertexFormat = 21
	VertexFormatSnorm16x2       VertexFormat = 22
	VertexFormatSnorm16x4       VertexFormat = 23
	VertexFormatFloat16         VertexFormat = 24
	VertexFormatFloat16x2       VertexFormat = 25
	VertexFormatFloat16x4       VertexFormat = 26
	VertexFormatFloat32         VertexFormat = 27
	VertexFormatFloat32x2       VertexFormat = 28
	VertexFormatFloat32x3       VertexFormat = 29
	VertexFormatFloat32x4       VertexFormat = 30
	VertexFormatUint32          VertexFormat = 31
	VertexFormatUint32x2        VertexFormat = 32
	VertexFormatUint32x3        VertexFormat = 33
	VertexFormatUint32x4        VertexFormat = 34
	VertexFormatSint32          VertexFormat = 35
	VertexFormatSint32x2        VertexFormat = 36
	VertexFormatSint32x3        VertexFormat = 37
	VertexFormatSint32x4        VertexFormat = 38
	VertexFormatUnorm10_10_10_2 VertexFormat = 43
	VertexFormatUnorm8x4Bgra    VertexFormat = 44
	VertexFormatSnorm10_10_10_2 VertexFormat = 45
)

type VertexPullingOptions added in v0.21.0

type VertexPullingOptions struct {
	// VertexBuffers describes the vertex buffers and their attributes.
	VertexBuffers []VertexBufferMapping
}

VertexPullingOptions configures vertex pulling: the vertex buffers vertex entry points read their inputs from.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL