Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2021 Developer ToolsGraphics & Games

WWDC21 · 32 min · Developer Tools / Graphics & Games

Optimize high-end games for Apple GPUs

Optimize your high-end games for Apple GPUs: We’ll show you how you can use our rendering and debugging tools to eliminate performance issues and make your games great on Apple platforms. Learn from our experiences working with developers at Larian Studios and 4A Games as we help them optimize their games for Apple GPUs. We’ll explore various techniques for improving your game’s performance, including optimizing shaders, reducing memory bandwidth utilization, and increasing the overlap of your GPU workloads. We’ll also dive into the new GPU Timeline profiling tool in Xcode 13 to identify possible performance bottlenecks in “Divinity: Original Sin 2” when running on iPad. For this session, you should be familiar with the tile-based deferred rendering architecture in Apple GPUs, and have a working knowledge of Xcode and the Metal API. Check out “Discover Metal debugging, profiling, and asset creation tools” or the WWDC20 session “Optimize Metal apps and games with GPU counters” to learn more about using our tools to profile graphics workloads.

Watch at developer.apple.com ↗

Transcript all transcripts

Code shown on screen · 2 snippets

Pseudocode to choose shared and private buffer count objectivec · at 15:24 ↗
// Number of frames application is processing
static const uint32_t MAX_FRAMES_IN_FLIGHT = 3;

uint32_t sharedBuffersCount  = 0; // Number of buffers with MTLStorageModeShared to create
uint32_t privateBuffersCount = 0; // Number of buffers with MTLStorageModePrivate to create
if (device.hasUnifiedMemory)
{
    // Use extra buffer to reduce impact of completion handler
    sharedBuffersCount = MAX_FRAMES_IN_FLIGHT + 1;
    privateBuffersCount = 0;
}
else // GPUs with dedicated memory
{
    sharedBuffersCount = MAX_FRAMES_IN_FLIGHT;
    privateBuffersCount = 1;
}

// Create shared buffers MTLStorageModeShared
// If applicable, create private buffer
Pseudocode to avoid redundant bindings objectivec · at 21:40 ↗
void Renderer::SetFragmentTexture(uint32_t index, id<MTLTexture> texture)
{
    if (m_FragmentTextures[index] != texture)
    {
        m_FragmentTextures[index] = texture;
        m_FragmentTexturesChanged = true;
    }
}

void Renderer::BindFragmentTextures()
{
    if (m_FragmentTexturesChanged)
    {
        [m_RenderCommandEncoder setFragmentTextures:m_FragmentTextures 
                          withRange:NSMakeRange(0, m_LastFragmentTexture + 1)];

        m_FragmentTexturesChanged = false;
    }
}

Resources