20 years Weta/Pixar experience in real-time graphics, Metal shaders, and visual effects. Expert in MSL shaders, PBR rendering, tile-based deferred rendering (TBDR), and GPU debugging. Activate on 'Metal shader', 'MSL', 'compute shader', 'vertex shader', 'fragment shader', 'PBR', 'ray tracing', 'tile shader', 'GPU profiling', 'Apple GPU'. NOT for WebGL/GLSL (different architecture), general OpenGL (deprecated on Apple), CUDA (NVIDIA only), or CPU-side rendering optimization.
Instrucciones de origen · Vista previa de solo lectura
license
Apache-2.0
name
metal-shader-expert
description
20 years Weta/Pixar experience in real-time graphics, Metal shaders, and visual effects. Expert in MSL shaders, PBR rendering, tile-based deferred rendering (TBDR), and GPU debugging. Activate on 'Metal shader', 'MSL', 'compute shader', 'vertex shader', 'fragment shader', 'PBR', 'ray tracing', 'tile shader', 'GPU profiling', 'Apple GPU'. NOT for WebGL/GLSL (different architecture), general OpenGL (deprecated on Apple), CUDA (NVIDIA only), or CPU-side rendering optimization.
{"category":"Frontend & UI","tags":["metal","shaders","gpu","graphics","apple"],"provenance":{"kind":"first-party","owners":["port-daddy"]},"pairs-with":[{"skill":"gpui-shaders","reason":"gpui renders its custom widgets through Metal shaders on macOS; this skill supplies the MSL/TBDR expertise those shaders need."},{"skill":"metal-text-pipeline","reason":"Text rendering pipelines share the same precision/TBDR trade-offs (half vs float, tile memory) this skill's decision matrices cover."},{"skill":"vello-parley-rendering","reason":"GPU vector-graphics rendering needs the same bandwidth/occupancy discipline for compute and tile shaders."},{"skill":"rust-gpui-motion","reason":"Animated gpui UI often drives per-frame shader parameters; this skill's failure modes (branch divergence, register pressure) apply directly."}],"io-contract":{"kind":"deliverable","consumes":["[Truncated]","[Truncated]"],"produces":["[Truncated]","[Truncated]"]}}
Metal Shader Expert
20+ years Weta/Pixar experience specializing in Metal shaders, real-time rendering, and creative visual effects. Expert in Apple's Tile-Based Deferred Rendering (TBDR) architecture.
Decision Points
Shader Type Selection Matrix
Massive parallel data processing:
If data-independent operations → Compute shader (threadgroup size = data size)
If per-pixel operations with neighbor access → Tile shader
If simple per-vertex transformations → Vertex shader
If per-pixel lighting/materials → Fragment shader
Memory access patterns:
If reading multiple textures per pixel → Fragment shader (tile cache optimized)
If writing to multiple render targets → Fragment shader with [[color(n)]]
If sharing data between nearby threads → Tile shader with threadgroup memory
If sequential processing → Compute shader with atomic operations
If ALU-limited (heavy computation) → Compute shader (more threads)
If geometry-limited → Vertex shader with instancing/amplification
Memory/Precision Trade-off Decision Tree
Input: Variable type needed
├── Position/depth calculations?
│ └── YES: Use `float` (32-bit precision required)
├── Color/normal calculations?
│ ├── HDR/wide gamut? → `float`
│ └── Standard range? → `half` (saves 50% registers)
├── Iteration counters/indices?
│ └── Use `uint16_t` or `ushort` when possible
└── Temporary calculations?
├── Intermediate precision needed? → `float`
└── Display-bound result? → `half`
TBDR Architecture Decisions
Render target strategy:
If intermediate data not needed after pass → Memoryless texture (MTLStorageModeMemoryless)
If ping-ponging between targets → Use tile shader to avoid store/load
If multiple render targets → Group related data to minimize bandwidth
Failure Modes
1. "Bandwidth Bandit" - Excessive Memory Traffic
Detection: Frame debugger shows high memory bandwidth, low ALU utilization
Symptoms: Multiple texture fetches per fragment, storing unnecessary render targets
Fix: Use tile shaders for multi-pass effects, memoryless targets for intermediate data
// BAD: Multiple passes with full store/load
float4 pass1_result = sample_texture(tex1, uv);
// Store to render target, then load in next pass
// GOOD: Tile shader keeps data in tile memory
threadgroup float4 tile_data[64];
// Process multiple steps without memory round-trip
2. "Register Pressure Cascade" - Poor Data Type Choices
Detection: GPU occupancy drops below 50%, register spilling in shader profiler
Symptoms: Using float4 everywhere, large intermediate arrays
Fix: Use half for display-bound calculations, pack data efficiently
Detection: Fragment shader shows low efficiency in GPU profiler
Symptoms:if/else statements based on material properties or uniforms
Fix: Use function constants for compile-time specialization
// BAD: Runtime branching
if (material.has_normal_map) { /* complex normal mapping */ }
// GOOD: Function constant
constant bool has_normal_map [[function_constant(0)]];
if (has_normal_map) { /* branch eliminated at compile time */ }
Detection: Memory bandwidth higher than expected, register usage at 100%
Symptoms:float used for colors, normals, and other display-bound values
Fix: Default to half, upgrade only when precision artifacts appear
Detection: Ray tracing performance significantly below expectations
Symptoms: Using intersection query API instead of intersector
Fix: Use intersector API with explicit result handling for hardware alignment
Worked Examples
Example 1: PBR Fragment Shader Optimization
Initial novice implementation:
fragment float4 pbr_fragment(VertexOut in [[stage_in]],
constant Material& material [[buffer(0)]],
texture2d<float> albedo_tex [[texture(0)]]) {
float4 albedo = albedo_tex.sample(sampler, in.uv);
float3 normal = normalize(in.normal);
// ... complex BRDF calculation using float everywhere
return float4(final_color, 1.0);
}
Expert decision process:
Precision analysis: Color output is display-bound → use half for most calculations
Register optimization: Pack material properties, use half for intermediate values
TBDR optimization: Multiple material variants → use function constants
Optimized implementation:
constant bool use_normal_map [[function_constant(0)]];
constant bool use_metallic_roughness [[function_constant(1)]];
fragment half4 pbr_fragment(VertexOut in [[stage_in]],
constant MaterialHalf& material [[buffer(0)]],
texture2d<half> albedo_tex [[texture(0)]]) {
half4 albedo = albedo_tex.sample(sampler, in.uv);
half3 normal = normalize(half3(in.normal)); // Only convert once
if (use_normal_map) {
// Normal mapping branch eliminated at compile time
}
// BRDF calculation in half precision
half3 final_color = calculate_brdf_half(albedo.rgb, normal, material);
return half4(final_color, albedo.a);
}
Performance impact: 40% reduction in register usage, 2x occupancy increase
references/debug-tools.md — heat maps, debug visualization modes, overdraw/mipmap/NaN detection, live value inspector, performance profiler overlay.
references/production-and-performance.md — Weta/Pixar artist-facing material authoring, procedural surface variation, the bandwidth/ALU/occupancy/divergence profiling mental model, and the debug-tooling checklist.
Deterministic Shader-Perf Auditor
Given a JSON shader plan (see schemas/shader-plan.schema.json), run the
auditor to catch this skill's five failure modes mechanically instead of by
eye:
It flags bandwidth-bandit multi-pass store/load, float-for-display-bound
precision overkill, low occupancy / high register usage, runtime branching on
a uniform instead of a function constant, tile memory over the 32KB limit,
and threadgroup sizes that aren't a multiple of 32. Use templates/output-template.md
to write the optimized-shader implementation guide this skill produces.
NOT-FOR Boundaries
Wrong platforms/APIs:
WebGL/OpenGL ES: Use webgl-shader-expert - different precision rules, extension handling
CUDA/OpenCL: Use gpu-compute-expert - different memory model, NVIDIA-specific optimizations
Vulkan/DirectX: Use graphics-api-expert - immediate-mode renderer assumptions
Wrong abstraction level:
CPU optimization: Use performance-engineering - different bottlenecks, memory patterns
Engine architecture: Use game-engine-expert - render graph design, asset pipelines
Platform-agnostic graphics: Use graphics-programming - need Apple-specific TBDR knowledge
Wrong problem scope:
UI/2D graphics: Use native-app-designer - Core Animation, simpler shaders sufficient
Scientific computing: Use scientific-computing - different precision/accuracy requirements
Web graphics: Use web-graphics-expert - browser constraints, WebGPU considerations
Master Metal shaders with the precision of film production and the performance demands of real-time interaction.
Skill Bundle Index
Every file in this skill, and when to open it. Auto-generated; run scripts/index_references.py --fix.
root
CHANGELOG.md — Changelog — - Frontmatter moved category/tags/pairs-with under a metadata block and added metadata.provenance (first-party, port-daddy) and `m
README.md — Metal Shader Expert — 20+ years Weta/Pixar-style experience specializing in Metal shaders, real-time rendering, and Apple's Tile-Based Deferred Rendering (TBDR) a
references/debug-tools.md — Debug Tools & Visualization — Essential patterns for shader debugging and performance analysis.
references/noise-effects.md — Noise-Based Effects — Organic, procedural effects using noise functions in Metal.
references/pbr-shaders.md — PBR Shader Implementation — Complete Cook-Torrance BRDF implementation in Metal Shading Language.
references/production-and-performance.md — Production Techniques & Performance Mental Model — Weta/Pixar-style production shader authoring, a bandwidth/ALU/occupancy/divergence profiling mental model, and the debug-tooling checklist t