Skip to content

Blaze3D API Reference

Blaze3D is Minecraft 26.1’s graphics abstraction layer that provides a clean interface between game code and graphics APIs. This reference covers all major Blaze3D classes, methods, and usage patterns.

The main entry point for Blaze3D functionality.

com.mojang.blaze3d.Blaze3D
public final class Blaze3D {
private Blaze3D() {
// Private constructor - utility class
}
/**
* Returns the current time in milliseconds since startup.
* Used for animation timing and effects.
*/
public static long getTime() {
return System.nanoTime() / 1000000L;
}
/**
* Easter egg method - displays game over message.
* Not typically used in modding.
*/
public static String youJustLostTheGame() {
return new Random().nextFloat() < 0.025F ? "You just lost The Game!" : null;
}
}

Usage Example:

// Example: Animation timing using Blaze3D
public void renderAnimatedEffect(float partialTick) {
long currentTime = Blaze3D.getTime();
float animationTime = (currentTime % 2000L) / 1000.0f;
float pulseValue = (float) Math.sin(animationTime * Math.PI);
// Use pulse value for visual effects
setEffectIntensity(pulseValue);
}

The central coordinator for all rendering operations and state management.

com.mojang.blaze3d.systems.RenderSystem
public final class RenderSystem {
private static final Thread MAIN_RENDER_THREAD = Thread.currentThread();
private static GpuDevice device;
/**
* Checks if the current thread is the render thread.
* All rendering operations must be called from the render thread.
*/
public static boolean isOnRenderThread() {
return Thread.currentThread() == MAIN_RENDER_THREAD;
}
/**
* Throws IllegalStateException if not on render thread.
* Used for debugging and ensuring thread safety.
*/
public static void assertOnRenderThread() {
if (!isOnRenderThread()) {
throw new IllegalStateException("Not on render thread");
}
}
/**
* Gets the current graphics device instance.
* Used to create GPU resources.
*/
public static GpuDevice getDevice() {
if (device == null) {
device = createGpuDevice();
}
return device;
}
/**
* Sets up the projection matrix for 2D GUI rendering.
* @param width Screen width
* @param height Screen height
*/
public static void setProjectionGui(int width, int height) {
Matrix4f matrix = new Matrix4f();
matrix.setOrthographic(0.0F, width, height, 0.0F, 2000.0F);
setProjectionMatrix(matrix);
}
/**
* Applies a translation transformation to the current matrix stack.
* @param x X offset
* @param y Y offset
* @param z Z offset
*/
public static void translatef(double x, double y, double z) {
RenderSystem.assertOnRenderThread();
getMatrixStack().translate(x, y, z);
}
/**
* Applies a rotation transformation around an axis.
* @param angle Rotation angle in degrees
* @param x X component of rotation axis
* @param y Y component of rotation axis
* @param z Z component of rotation axis
*/
public static void rotatef(float angle, float x, float y, float z) {
RenderSystem.assertOnRenderThread();
getMatrixStack().mulPose(Axis.of(new Vec3(x, y, z)).rotationDegrees(angle));
}
/**
* Applies a scale transformation.
* @param x X scale factor
* @param y Y scale factor
* @param z Z scale factor
*/
public static void scalef(float x, float y, float z) {
RenderSystem.assertOnRenderThread();
getMatrixStack().scale(x, y, z);
}
/**
* Sets the current shader for rendering operations.
* @param shader Supplier that provides the shader instance
*/
public static void setShader(Supplier<ShaderInstance> shader) {
RenderSystem.assertOnRenderThread();
ShaderInstance instance = shader.get();
if (instance != null) {
instance.apply();
}
}
/**
* Sets shader color multiplier.
* @param r Red component (0-1)
* @param g Green component (0-1)
* @param b Blue component (0-1)
* @param a Alpha component (0-1)
*/
public static void setShaderColor(float r, float g, float b, float a) {
RenderSystem.assertOnRenderThread();
ShaderInstance shader = getInstance().getShader();
if (shader != null) {
shader.safeGetUniform("Color").set(r, g, b, a);
}
}
}

Usage Examples:

// Example: Safe rendering with proper state management
public void renderCustomGeometry() {
RenderSystem.assertOnRenderThread();
// Save current state
RenderSystem.pushMatrix();
// Apply transformations
RenderSystem.translatef(x, y, z);
RenderSystem.rotatef(angle, 0.0F, 1.0F, 0.0F);
RenderSystem.scalef(scale, scale, scale);
// Set shader and color
RenderSystem.setShader(GameRenderer::getPositionColorShader);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
// Render geometry
renderGeometry();
// Restore state
RenderSystem.popMatrix();
}
// Example: Thread-safe operation
public void scheduleRenderOperation(Runnable operation) {
if (RenderSystem.isOnRenderThread()) {
operation.run();
} else {
Minecraft.getInstance().execute(operation);
}
}

Abstract interface for GPU device operations.

com.mojang.blaze3d.systems.GpuDevice
public interface GpuDevice {
/**
* Creates a GPU buffer with specified type and usage flags.
* @param type Buffer type (VERTEX, INDEX, UNIFORM, etc.)
* @param usage Usage flags (MAP_READ, MAP_WRITE, etc.)
* @return New GPU buffer instance
*/
GpuBuffer createBuffer(GpuBuffer.BufferType type, long usage);
/**
* Creates a GPU texture with specified properties.
* @param type Texture type (TEXTURE_2D, TEXTURE_CUBE_MAP, etc.)
* @param width Texture width in pixels
* @param height Texture height in pixels
* @param usage Usage flags (TEXTURE_BINDING, RENDER_ATTACHMENT, etc.)
* @return New GPU texture instance
*/
GpuTexture createTexture(GpuTexture.TextureType type, int width, int height, long usage);
/**
* Creates a texture sampler with specified properties.
* @param wrapU U-axis wrap mode
* @param wrapV V-axis wrap mode
* @param minFilter Minification filter
* @param magFilter Magnification filter
* @return New sampler instance
*/
GpuSampler createSampler(GpuSampler.WrapMode wrapU, GpuSampler.WrapMode wrapV,
GpuSampler.MinFilter minFilter, GpuSampler.MagFilter magFilter);
/**
* Compiles and creates a shader from specified sources.
* @param name Shader identifier
* @param vertexSource Vertex shader source code
* @param fragmentSource Fragment shader source code
* @return Compiled shader instance
*/
ShaderInstance compileShader(String name, String vertexSource, String fragmentSource);
/**
* Executes a task with GPU synchronization.
* @param fence Fence for synchronization
* @param task Task to execute
*/
void queueFencedTask(GpuFence fence, Runnable task);
/**
* Returns device capabilities and features.
* @return Device capabilities object
*/
DeviceCapabilities getCapabilities();
}

Usage Example:

// Example: Creating GPU resources through device
public class ResourceCreator {
private final GpuDevice device;
private GpuBuffer vertexBuffer;
private GpuTexture texture;
private GpuSampler sampler;
public ResourceCreator() {
this.device = RenderSystem.getDevice();
}
public void createResources() {
RenderSystem.assertOnRenderThread();
// Create vertex buffer
this.vertexBuffer = device.createBuffer(
GpuBuffer.BufferType.VERTEX,
GpuBuffer.Usage.STATIC_DRAW
);
// Create texture
this.texture = device.createTexture(
GpuTexture.TextureType.TEXTURE_2D,
256, 256,
GpuTexture.Usage.TEXTURE_BINDING | GpuTexture.Usage.COPY_SRC
);
// Create sampler
this.sampler = device.createSampler(
GpuSampler.WrapMode.REPEAT,
GpuSampler.WrapMode.REPEAT,
GpuSampler.MinFilter.LINEAR,
GpuSampler.MagFilter.LINEAR
);
// Upload data to resources
uploadResourceData();
}
}

Abstract base class for GPU memory buffers.

com.mojang.blaze3d.buffers.GpuBuffer
public abstract class GpuBuffer implements AutoCloseable {
public enum BufferType {
VERTEX, // Vertex data buffer
INDEX, // Index data buffer
UNIFORM, // Uniform data buffer
STORAGE // Storage buffer (if supported)
}
public enum UsageFlag {
MAP_READ(1L), // Buffer can be read by CPU
MAP_WRITE(2L), // Buffer can be written by CPU
COPY_SRC(4L), // Buffer can be copy source
COPY_DST(8L), // Buffer can be copy destination
VERTEX(16L), // Buffer can be vertex binding
INDEX(32L), // Buffer can be index binding
UNIFORM(64L); // Buffer can be uniform binding
public final long mask;
UsageFlag(long mask) { this.mask = mask; }
}
/**
* Binds this buffer to the specified binding point.
* @param binding Binding point index
*/
public abstract void bind(int binding);
/**
* Unbinds this buffer from the current binding point.
*/
public abstract void unbind();
/**
* Uploads data to this buffer.
* @param data Byte buffer containing data to upload
*/
public abstract void upload(ByteBuffer data);
/**
* Uploads a portion of data to this buffer.
* @param offset Offset in bytes from buffer start
* @param data Byte buffer containing data to upload
*/
public abstract void upload(long offset, ByteBuffer data);
/**
* Creates a slice view into this buffer.
* @param offset Offset in bytes from buffer start
* @param length Length of slice in bytes
* @return Buffer slice view
*/
public abstract GpuBufferSlice slice(long offset, long length);
/**
* Maps this buffer for CPU access.
* @param access Access mode (READ_ONLY, WRITE_ONLY, READ_WRITE)
* @return Mapped memory buffer
*/
public abstract ByteBuffer map(GpuBuffer.MapAccess access);
/**
* Unmaps this buffer from CPU access.
*/
public abstract void unmap();
/**
* Gets the size of this buffer in bytes.
* @return Buffer size
*/
public abstract long getSize();
/**
* Closes and releases this buffer's GPU resources.
*/
public abstract void close();
}

Usage Example:

// Example: Creating and using a vertex buffer
public class VertexBufferExample {
private GpuBuffer vertexBuffer;
private final GpuDevice device;
public VertexBufferExample() {
this.device = RenderSystem.getDevice();
}
public void createVertexBuffer(float[] vertices) {
RenderSystem.assertOnRenderThread();
// Create buffer with appropriate usage flags
this.vertexBuffer = device.createBuffer(
GpuBuffer.BufferType.VERTEX,
GpuBuffer.Usage.STATIC_DRAW | GpuBuffer.Usage.MAP_WRITE
);
// Convert float array to byte buffer
ByteBuffer byteBuffer = BufferUtils.createFloatBuffer(vertices.length);
byteBuffer.asFloatBuffer().put(vertices).flip();
// Upload data
vertexBuffer.upload(byteBuffer);
}
public void renderBuffer() {
RenderSystem.assertOnRenderThread();
// Bind buffer for drawing
vertexBuffer.bind();
// Issue draw call
int vertexCount = (int)(vertexBuffer.getSize() / (6 * Float.BYTES)); // 6 floats per vertex
GL11.glDrawArrays(GL11.GL_QUADS, 0, vertexCount);
// Unbind
vertexBuffer.unbind();
}
public void cleanup() {
if (vertexBuffer != null) {
vertexBuffer.close();
}
}
}

High-performance vertex data construction utility.

com.mojang.blaze3d.vertex.BufferBuilder
public class BufferBuilder {
private final VertexFormat format;
private ByteBuffer buffer;
private int vertexCount;
private boolean building;
/**
* Begins vertex data construction with specified format and mode.
* @param mode Drawing mode (QUADS, TRIANGLES, LINES, etc.)
* @param format Vertex data format
*/
public void begin(VertexFormat.Mode mode, VertexFormat format) {
if (this.building) {
throw new IllegalStateException("Already building");
}
this.mode = mode;
this.format = format;
this.vertexCount = 0;
this.buffer = MemoryUtil.malloc(this.format.getVertexSize() * 65536);
this.building = true;
}
/**
* Adds a vertex with position data.
* @param x X coordinate
* @param y Y coordinate
* @param z Z coordinate
* @return BufferBuilder for chaining
*/
public BufferBuilder vertex(float x, float y, float z) {
if (!this.building) {
throw new IllegalStateException("Not building");
}
ensureCapacity(this.format.getVertexSize());
writePosition(x, y, z);
return this;
}
/**
* Adds color data to current vertex.
* @param r Red component (0-255)
* @param g Green component (0-255)
* @param b Blue component (0-255)
* @param a Alpha component (0-255)
* @return BufferBuilder for chaining
*/
public BufferBuilder color(int r, int g, int b, int a) {
if (!this.building) {
throw new IllegalStateException("Not building");
}
writeColor(r, g, b, a);
return this;
}
/**
* Adds texture coordinate data to current vertex.
* @param u U coordinate
* @param v V coordinate
* @return BufferBuilder for chaining
*/
public BufferBuilder uv(float u, float v) {
if (!this.building) {
throw new IllegalStateException("Not building");
}
writeUv(u, v);
return this;
}
/**
* Ends vertex data construction and returns result.
* @return RenderedBuffer containing vertex data
*/
public RenderedBuffer end() {
if (!this.building) {
throw new IllegalStateException("Not building");
}
this.building = false;
// Create final buffer with actual used size
ByteBuffer finalBuffer = MemoryUtil.malloc(this.buffer.position());
this.buffer.flip();
finalBuffer.put(this.buffer);
finalBuffer.flip();
return new RenderedBuffer(finalBuffer, this.vertexCount);
}
private static class RenderedBuffer {
public final ByteBuffer vertexBuffer;
public final int vertexCount;
RenderedBuffer(ByteBuffer vertexBuffer, int vertexCount) {
this.vertexBuffer = vertexBuffer;
this.vertexCount = vertexCount;
}
}
}

Usage Example:

// Example: Building complex geometry with BufferBuilder
public BufferBuilder.RenderedBuffer createCubeGeometry() {
BufferBuilder builder = new BufferBuilder(256);
builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_TEX);
// Front face
builder.vertex(-0.5f, -0.5f, 0.5f)
.color(255, 255, 255, 255)
.uv(0.0f, 0.0f)
.endVertex();
builder.vertex(0.5f, -0.5f, 0.5f)
.color(255, 255, 255, 255)
.uv(1.0f, 0.0f)
.endVertex();
builder.vertex(0.5f, 0.5f, 0.5f)
.color(255, 255, 255, 255)
.uv(1.0f, 1.0f)
.endVertex();
builder.vertex(-0.5f, 0.5f, 0.5f)
.color(255, 255, 255, 255)
.uv(0.0f, 1.0f)
.endVertex();
// Add remaining faces...
return builder.end();
}

Abstract base class for GPU texture resources.

com.mojang.blaze3d.textures.GpuTexture
public abstract class GpuTexture implements AutoCloseable {
public enum TextureType {
TEXTURE_1D, // 1D texture
TEXTURE_2D, // 2D texture (most common)
TEXTURE_3D, // 3D texture
TEXTURE_CUBE_MAP, // Cube map texture
TEXTURE_1D_ARRAY, // 1D texture array
TEXTURE_2D_ARRAY, // 2D texture array
TEXTURE_CUBE_MAP_ARRAY // Cube map array
}
public enum UsageFlag {
COPY_SRC(1L), // Texture can be copy source
COPY_DST(2L), // Texture can be copy destination
TEXTURE_BINDING(4L), // Texture can be bound for sampling
RENDER_ATTACHMENT(8L), // Texture can be render target
CUBEMAP_COMPATIBLE(16L); // Texture can be used as cube map
public final long mask;
UsageFlag(long mask) { this.mask = mask; }
}
/**
* Uploads image data to this texture.
* @param level Mipmap level (0 for base level)
* @param x X offset in pixels
* @param y Y offset in pixels
* @param width Image width in pixels
* @param height Image height in pixels
* @param format Pixel format
* @param buffer Image data buffer
*/
public abstract void upload(int level, int x, int y, int width, int height,
TextureFormat format, ByteBuffer buffer);
/**
* Creates a view into this texture.
* @param level Mipmap level
* @param layer Array layer or cube face
* @return Texture view
*/
public abstract GpuTextureView createView(int level, int layer);
/**
* Binds this texture to the specified texture unit.
* @param unit Texture unit index
*/
public abstract void bind(int unit);
/**
* Unbinds this texture.
*/
public abstract void unbind();
/**
* Generates mipmaps for this texture.
*/
public abstract void generateMipmaps();
/**
* Gets the texture width.
* @return Width in pixels
*/
public abstract int getWidth();
/**
* Gets the texture height.
* @return Height in pixels
*/
public abstract int getHeight();
/**
* Closes and releases this texture's GPU resources.
*/
public abstract void close();
}

Usage Example:

// Example: Creating and using textures
public class TextureManager {
private final Map<String, GpuTexture> textures = new HashMap<>();
private final GpuDevice device;
public TextureManager() {
this.device = RenderSystem.getDevice();
}
public void loadTexture(String name, BufferedImage image) {
RenderSystem.assertOnRenderThread();
// Convert image to byte buffer
ByteBuffer buffer = convertImageToBuffer(image);
// Create texture
GpuTexture texture = device.createTexture(
GpuTexture.TextureType.TEXTURE_2D,
image.getWidth(),
image.getHeight(),
GpuTexture.Usage.TEXTURE_BINDING | GpuTexture.Usage.COPY_SRC
);
// Upload image data
texture.upload(0, 0, 0, image.getWidth(), image.getHeight(),
TextureFormat.RGBA, buffer);
// Generate mipmaps
texture.generateMipmaps();
this.textures.put(name, texture);
}
public void bindTexture(String name, int unit) {
GpuTexture texture = textures.get(name);
if (texture != null) {
texture.bind(unit);
}
}
public void cleanup() {
for (GpuTexture texture : textures.values()) {
texture.close();
}
textures.clear();
}
}
// Example: RAII pattern for automatic resource cleanup
public class ScopedResource implements AutoCloseable {
private final GpuBuffer buffer;
private final GpuTexture texture;
public ScopedResource() {
this.buffer = RenderSystem.getDevice().createBuffer(
GpuBuffer.BufferType.VERTEX, GpuBuffer.Usage.STATIC_DRAW);
this.texture = RenderSystem.getDevice().createTexture(
GpuTexture.TextureType.TEXTURE_2D, 256, 256,
GpuTexture.Usage.TEXTURE_BINDING);
}
public GpuBuffer getBuffer() { return buffer; }
public GpuTexture getTexture() { return texture; }
@Override
public void close() {
if (buffer != null) buffer.close();
if (texture != null) texture.close();
}
}
// Usage with try-with-resources
public void renderWithScopedResources() {
RenderSystem.assertOnRenderThread();
try (ScopedResource resources = new ScopedResource()) {
// Use resources
resources.getTexture().bind(0);
resources.getBuffer().bind();
// Perform rendering
renderGeometry();
}
// Resources automatically cleaned up
}
// Example: Safe asynchronous resource creation
public class AsyncResourceCreator {
private CompletableFuture<GpuBuffer> bufferFuture;
public void createBufferAsync(float[] vertexData) {
// Convert to byte buffer on current thread
ByteBuffer byteBuffer = BufferUtils.createFloatBuffer(vertexData.length);
byteBuffer.asFloatBuffer().put(vertexData).flip();
// Schedule GPU resource creation on render thread
this.bufferFuture = CompletableFuture.supplyAsync(() -> {
GpuDevice device = RenderSystem.getDevice();
GpuBuffer buffer = device.createBuffer(
GpuBuffer.BufferType.VERTEX, GpuBuffer.Usage.STATIC_DRAW);
buffer.upload(byteBuffer);
return buffer;
}, Minecraft.getInstance());
}
public void whenReady(Consumer<GpuBuffer> callback) {
bufferFuture.thenAcceptAsync(callback, Minecraft.getInstance());
}
}
// Example: Buffer pool for reducing allocations
public class BufferPool {
private final Queue<GpuBuffer> availableBuffers = new ArrayDeque<>();
private final GpuDevice device;
private final int bufferSize;
public BufferPool(GpuDevice device, int bufferSize) {
this.device = device;
this.bufferSize = bufferSize;
}
public GpuBuffer acquire() {
RenderSystem.assertOnRenderThread();
GpuBuffer buffer = availableBuffers.poll();
if (buffer == null) {
buffer = device.createBuffer(
GpuBuffer.BufferType.VERTEX,
GpuBuffer.Usage.DYNAMIC_DRAW);
}
return buffer;
}
public void release(GpuBuffer buffer) {
RenderSystem.assertOnRenderThread();
if (availableBuffers.size() < 16) { // Limit pool size
availableBuffers.offer(buffer);
} else {
buffer.close();
}
}
public void cleanup() {
RenderSystem.assertOnRenderThread();
for (GpuBuffer buffer : availableBuffers) {
buffer.close();
}
availableBuffers.clear();
}
}

Problem: Memory usage increases over time Solution: Use proper resource management patterns and RAII

Problem: Crashes due to non-render thread operations Solution: Always use RenderSystem.assertOnRenderThread() and proper synchronization

Problem: Excessive buffer allocations Solution: Use buffer pooling and reuse resources

  1. Always check thread safety before using RenderSystem
  2. Use RAII patterns for automatic resource cleanup
  3. Pool buffers for frequently allocated resources
  4. Validate bounds when using buffer slices
  5. Cache resource references to avoid repeated lookups
  6. Profile GPU operations to identify bottlenecks