Skip to main content

SwapChain

A SwapChain represents an operating system’s native renderable surface (typically a window or view).

Overview

The SwapChain connects Filament to a native OS window for presentation. Because it’s initialized from a native object, the type of the pointer varies by platform.

Platform-specific native window types

When using Engine::create() without a custom Platform, the nativeWindow parameter must be:
PlatformNative window type
AndroidANativeWindow*
macOS (OpenGL)NSView*
macOS (Metal)CAMetalLayer*
iOS (OpenGL)CAEAGLLayer*
iOS (Metal)CAMetalLayer*
X11Window
WindowsHWND

Creation and destruction

Create using Engine::createSwapChain() and destroy using Engine::destroy():
#include <filament/SwapChain.h>
#include <filament/Engine.h>
using namespace filament;

Engine* engine = Engine::create();

// From native window
SwapChain* swapChain = engine->createSwapChain(nativeWindow);

// ... use swap chain ...

engine->destroy(swapChain);

Creating swap chains

From native window

nativeWindow
void*
Platform-specific native window handle
flags
uint64_t
default:"0"
Optional configuration flags
SwapChain* swapChain = engine->createSwapChain(nativeWindow);

// With flags
SwapChain* swapChain = engine->createSwapChain(
    nativeWindow, 
    SwapChain::CONFIG_TRANSPARENT
);

Headless swap chain

Create an off-screen swap chain without a window:
width
uint32_t
Width in pixels
height
uint32_t
Height in pixels
// 1920x1080 headless swap chain
SwapChain* offscreen = engine->createSwapChain(1920, 1080);

Configuration flags

CONFIG_TRANSPARENT

Create a transparent swap chain (composited with window system):
SwapChain* swapChain = engine->createSwapChain(
    nativeWindow,
    SwapChain::CONFIG_TRANSPARENT
);

CONFIG_READABLE

Make the swap chain readable (for screenshot capture):
SwapChain* swapChain = engine->createSwapChain(
    nativeWindow,
    SwapChain::CONFIG_READABLE
);

CONFIG_SRGB

Request an sRGB color space:
SwapChain* swapChain = engine->createSwapChain(
    nativeWindow,
    SwapChain::CONFIG_SRGB_COLORSPACE
);

Platform examples

Android

Get ANativeWindow* from Java Surface:
#include <android/native_window_jni.h>

// In JNI function:
// env:     JNIEnv*
// surface: jobject (Surface)
ANativeWindow* win = ANativeWindow_fromSurface(env, surface);

SwapChain* swapChain = engine->createSwapChain(win);
From TextureView:
// Java side
public void onSurfaceTextureAvailable(
        SurfaceTexture surfaceTexture, int width, int height) {
    mSurface = new Surface(surfaceTexture);
    // Pass mSurface to JNI to create ANativeWindow
}

Linux (X11)

Using SDL:
#include <SDL_syswm.h>

SDL_SysWMinfo wmi;
SDL_VERSION(&wmi.version);
SDL_GetWindowWMInfo(sdlWindow, &wmi);
Window nativeWindow = (Window) wmi.info.x11.window;

SwapChain* swapChain = engine->createSwapChain((void*) nativeWindow);

Windows

Using SDL:
#include <SDL_syswm.h>

SDL_SysWMinfo wmi;
SDL_VERSION(&wmi.version);
SDL_GetWindowWMInfo(sdlWindow, &wmi);
HWND nativeWindow = wmi.info.win.window;

SwapChain* swapChain = engine->createSwapChain((void*) nativeWindow);

macOS

Using SDL (OpenGL):
#include <Cocoa/Cocoa.h>
#include <SDL_syswm.h>

SDL_SysWMinfo wmi;
SDL_VERSION(&wmi.version);
SDL_GetWindowWMInfo(sdlWindow, &wmi);

NSWindow* win = (NSWindow*) wmi.info.cocoa.window;
NSView* view = [win contentView];
void* nativeWindow = view;

SwapChain* swapChain = engine->createSwapChain(nativeWindow);
For Metal backend, provide CAMetalLayer* instead.

iOS

Using UIKit:
#include <UIKit/UIKit.h>

UIView* view = ...; // Your view
CAMetalLayer* metalLayer = (CAMetalLayer*) view.layer;

SwapChain* swapChain = engine->createSwapChain(metalLayer);

Frame presentation

The swap chain is presented automatically when Renderer::endFrame() is called:
if (renderer->beginFrame(swapChain)) {
    renderer->render(view);
    renderer->endFrame();  // Presents to swap chain
}

Frame callbacks

Register callbacks for frame events:
void frameCallback(void* user) {
    std::cout << "Frame presented" << std::endl;
}

swapChain->setFrameScheduledCallback(frameCallback, nullptr);
swapChain->setFrameCompletedCallback(frameCallback, nullptr);

Recreating swap chains

When a window is resized or recreated, destroy and recreate the swap chain:
// Window resized
engine->destroy(swapChain);
swapChain = engine->createSwapChain(newNativeWindow);
Always destroy the old swap chain before creating a new one for the same window.

Reading pixels

With CONFIG_READABLE flag, you can read pixels:
SwapChain* swapChain = engine->createSwapChain(
    nativeWindow,
    SwapChain::CONFIG_READABLE
);

// After rendering
if (renderer->beginFrame(swapChain)) {
    renderer->render(view);
    
    // Read pixels (must be in beginFrame/endFrame)
    uint32_t width = 1920, height = 1080;
    size_t size = width * height * 4; // RGBA8
    uint8_t* pixels = new uint8_t[size];
    
    backend::PixelBufferDescriptor buffer(
        pixels, size,
        backend::PixelDataFormat::RGBA,
        backend::PixelDataType::UBYTE
    );
    
    renderer->readPixels(0, 0, width, height, std::move(buffer));
    
    renderer->endFrame();
}

Renderer

Frame rendering

Engine

Main entry point

Platform guides

Platform-specific setup

RenderTarget

Off-screen rendering

Build docs developers (and LLMs) love