Chapters

Hide chapters

Metal by Tutorials

Fifth Edition · macOS 26, iOS 26 · Swift 6, Metal 3 · Xcode 26

Section I: Beginning Metal

Section 1: 10 chapters
Show chapters Hide chapters

Section II: Intermediate Metal

Section 2: 8 chapters
Show chapters Hide chapters

Section III: Advanced Metal

Section 3: 8 chapters
Show chapters Hide chapters

25. Managing Resources
Written by Marius Horga & Caroline Begbie

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

So far, you’ve created an engine where you can load complex models with textures and materials, animate or update them per frame and render them. Your scenes will start to get more and more complicated as you develop your game, and you’ll want to find more performant ways of doing things and organizing your game resources.

Instead of processing each submesh and laboriously moving each of the submesh’s textures to the GPU, you’ll take advantage of the centralization of your textures in the Texture Controller. By the end of the chapter, you’ll be able to move all your textures to the GPU at once with just one render encoder command.

The secret sauce behind this process is indirection using argument buffers and a texture heap.

You’ll learn more about these things soon, but in brief, an argument buffer represents data that can match a shader structure. You can send the argument buffer to a shader function with one command, instead of sending each of the structure components individually.

An argument buffer containing resources
An argument buffer containing resources

A heap is exactly what it sounds like. You gather up your resources, such as textures and buffers, into an area of memory called a heap. You can then send this heap to the GPU with one command.

A heap containing textures
A heap containing textures

The Starter Project

With the basic idea under your belt, you’re ready to get started.

➤ In Xcode, open up the starter project for this chapter and build and run it.

You’ll see medieval buildings with some skeletal walkers roaming around menacingly.

The project consolidates many of the features that you’ve learned so far:

  • Shadows
  • IBL Lighting with sky box
  • Animation
  • Alpha testing
  • Textured models
  • Models with materials but no textures

There are a few added nifty features:

  1. Shadows are now soft shadows with PCF filtering.

  2. In the Textures folder, in TextureController.swift, TextureController has an extra level of indirection. The old textures dictionary is now named textureIndex and it holds indices into an array of textures.

When you load a submesh texture using TextureController, if the texture doesn’t exist by name already, TextureController adds the texture to the textures array, stores the array index and name into textureIndex and returns the index to the submesh. If the texture already exists by name, then the submesh simply holds the existing array index to the texture.

This stores all the app textures in one central array, making it easier to process into a heap later.

  1. When setting up character joint animation, you used function constants when you defined the pipeline state for the vertex shader. The shadow pipeline state repeats this process to render animated shadows.

  2. In the Render Passes folder, ShadowRenderPass and ForwardRenderPass sets a render pass state when rendering each model. The model then sets the correct mesh pipeline state depending on this render pass state, whether it is shadow or main.

Argument Buffers

When rendering a submesh, you currently send up to six textures and a material individually to the GPU for the fragment shader: Base color, normal, roughness, metalness, ambient occlusion and opacity textures. During the frame render loop, each of the textures requires a renderEncoder.setFragmentTexture(texture:at:) command.

E tiwlik tvix howm
E mimxab nhas qefc

Creating the Shader Structure

➤ In the Shaders folder, open IBL.metal.

Creating the Argument Buffer

Now you’ll set up the argument buffer containing all the texture resource IDs in Swift.

Updating the Draw Call

➤ In the Renderer folder, open Rendering.swift. This holds the extension on Model, where you render each model.

NXI irlept
MYI ubtojc

BCE eqniys
LBA ulmips

Ebubx agbekazv cohmehg
Akipb asmomumh nugmayf

Arcowigt Qiyuazduk
Imroxosj Qugoeqbov

Xhaahc kcoqo yuwdiqal
Vneiyc ldodi cerkiqeg

Resource Heaps

You’ve grouped textures into an argument buffer for each submesh, but you can also combine all your app’s textures into a resource heap.

The Blit Command Encoder

To blit means to copy from one part of memory to another and is typically an extremely fast operation. You create a blit command encoder using a command buffer, just as you did the render and compute command encoders. You then use this encoder when you want to copy a resource such as a texture or Metal buffer.

Fhabehitx ot yiyuda
Wlomuhevl ad yukece

Lunrocetq rodr o xezxabu couy
Qeqdotaty nujb e biqpasi fiur

Residency Sets

So far, you’ve moved your texture binding process from each submesh to each draw call. This is a significant improvement in the number of commands made per frame. For texture and buffer resources that could be resident on the GPU throughout your app, or throughout a game level in your app, you can utilize residency sets.

Key Points

  • An argument buffer is a collection of pointers to resources that you can pass to shaders.
  • A resource heap is a collection of textures or Metal buffers. A heap can be static, as in this chapter’s example, but you can also reuse space on the heap where you use different textures at different times.
  • A residency set allows you to group your resources and more easily control when they are available to the GPU.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2026 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now