MetalRender

This mod replaces Minecraft OpenGL rendering with Apple's own Metal. It increases Minecraft performance significantly! Only for macOS devices! Recommend to use 75% Render scale!
After MetalMod with 75% render scale

After MetalMod with 75% render scale

Before adding MetalMod

Before adding MetalMod

By_Frozen | MetalRender
Create your game server with affiliate logo
Create Server
affiliate banner image

Description

MetalMod

Minecraft, rendered in Metal. Natively. On your Mac.

Apple deprecated OpenGL in 2018. Minecraft still runs on it — through a translation layer, on a driver Apple stopped caring about years ago. MetalMod removes that layer entirely.

This is not a shader pack. It is not a config tweak. MetalMod rips out Blaze3D's OpenGL backend and replaces it with a hand-written Metal one. After the mod loads, your Minecraft client has no OpenGL context at all. The window is created with GLFW_NO_API, a CAMetalLayer is attached directly to the NSWindow, and every draw call in the game goes through Apple's native graphics API.

Then — because a tile-based Apple GPU rewards completely different things than a desktop GL driver does — MetalMod rebuilds how frames are submitted from the ground up.

The numbers

Measured on an M4, in-world, via the repo's benchmark harness (not eyeballed off the F3 screen):

Change    Before    After
Render encoders / frame    24.4    6.5
Frame time    8.35 ms    6.69 ms
Frame rate    120 fps    149 fps
Command buffers / frame    53    1.0
Terrain indices submitted    100%    48%

Command-buffer batching alone roughly doubled the frame rate over the naive port. Pass merging took another 20% on top. And that is before you touch a single setting in the options screen.

Features
Native Metal backend

MetalGpuDevice implements Mojang's own GpuDevice interface and is swapped in for vanilla's GlDevice at startup. Textures, buffers, samplers, fences, render passes, pipelines — all Metal objects, reached through a hand-written Objective-C++ JNI bridge (libmetalbridge.dylib), because LWJGL has no Metal binding and never will.

Render Scale — the biggest lever on a Retina Mac

Your MacBook's backing store is 2× the logical window. Fragment shading cost and per-pass attachment traffic both scale linearly with pixel count. Render the world at 75% and you pay 56% of native. At 50%, a quarter. The display scales it back up and the GUI stays pixel-perfect at full resolution.

Render pass merging

On a tile-based GPU, every render pass boundary reads the entire colour + depth attachment into tile memory and writes it back — ~26 MB each way at 1708×960. Vanilla opens a pass per immediate-mode draw, plus six for the sky. MetalMod defers pass closure and keeps encoding into the same MTLRenderCommandEncoder whenever the attachments match. 24.4 encoders per frame → 6.5.

Clear folding

A clear used to be its own encoder that wrote an attachment out, so the next pass could immediately read it back in. Two full round trips for nothing. Clears are now recorded and consumed by the following pass as its own loadAction = Clear — which on Apple silicon initialises the tile in place and costs zero bandwidth. ~4 encoders removed per frame on top of pass merging.

Native draw batching

Terrain is ~600 draws a frame, one per section per layer, each one a JNI + objc_msgSend round trip. MetalMod records the whole run into a direct ByteBuffer and replays it with a single JNI call. Recording defers, never reorders — anything unrecordable flushes the batch first and calls straight through.

Block Face Culling

Terrain quads are grouped by facing at upload time, so a draw submits only the facings the camera can actually see. 52% of terrain indices skipped, ~685 sections grouped. Only viable because the draw stream is batched natively.

Entity Culling

Ray-traces camera → bounding box and rejects entities and block entities fully hidden behind opaque blocks. Runs synchronously on the render thread inside vanilla's shouldRender, so it can never race ClientLevel — no background-thread flicker.

Advanced Chunk Culling

Bounds how many corners the section occlusion graph is allowed to turn. In open terrain it removes 8 of 6768 sections and stays out of your way; in caves and dense builds it earns its keep.

Fog Occlusion

Skips chunk sections buried inside environmental fog — water, lava, powder snow, blindness. Deliberately does not touch render-distance fog, which the section graph already handles.

Buffer renaming + pooling

Blaze3D keeps one GpuBuffer per vertex format and rewrites it for every immediate-mode draw — ~91,000 times in a 3-minute session. OpenGL survives that because the driver stalls or renames behind your back. Metal does not, and a raw memcpy lets draw N read draw N+1's vertices. MetalMod swaps in a fresh MTLBuffer per write and recycles them through a pool: 96% hit rate, ~7 MiB resident.

A real settings screen

MetalMod replaces vanilla's Video Settings wholesale, with every toggle above wired to something real and live-applied. Config lives in config/metalmod.json, separate from options.txt.

Requirements
macOS — Apple silicon or Intel Mac with Metal support. This mod is macOS-only by construction; there is no fallback path.
Minecraft 1.21.10 or 1.21.11 (separate jars — check the file you're downloading)
Fabric Loader 0.18.1+, Java 21
No Fabric API required. MetalMod deliberately has zero dependencies.

Shader translation runs at load time and needs two tools on your PATH:

brew install glslang spirv-cross

Without these, pipelines will not compile and the game will render nothing. This is the single most common install problem — do this step first.

How the shaders work

Blaze3D hands the backend GLSL. MetalMod runs it through glslangValidator -G → SPIR-V → spirv-cross --msl, then applies four textual fixes that spirv-cross does not do for you, each of which corresponds to a whole-screen-wrong bug:

Clip-space depth remap. Vanilla's projection is GL convention ([-w, w]); Metal wants [0, w]. Without this, Metal clips the near half of the frustum — terrain vanishes and you see sky through solid blocks.
Y-flip. Metal's framebuffer origin is top-left, GL's is bottom-left. Invisible on screen, extremely visible in render-to-texture — an unflipped lightmap samples its dark end and renders the entire world black.
Varying reconciliation. GLSL links varyings by name, Metal by location index, and spirv-cross numbers each stage independently. MetalMod re-matches them by name.
sampler rename. Vanilla's terrain.fsh uses sampler as a parameter name. It's a reserved type in MSL.

Generated MSL for every pipeline is dumped to $TMPDIR/metalmod-msl-debug/ if you want to read what your GPU is actually running.

Known limits
macOS only. Not a portability gap — a design constraint.
Vanilla shaders only. Iris/OptiFine shader packs are not supported.
Compatibility with other rendering mods is unlikely. MetalMod owns the entire graphics backend; anything that assumes an OpenGL context will not find one.
Pipelines that fail to compile degrade gracefully — their draws are skipped and logged, rather than crashing the client.

If something renders wrong, run/logs/latest.log almost always names the exact vanilla caller. Reports with a log attached get fixed; reports without one usually don't.

The MetalRender Team

profile avatar
  • 3
    Projects
  • 431
    Downloads

More from By_Frozen