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.
When using Engine::create() without a custom Platform, the nativeWindow parameter must be:
| Platform | Native window type |
|---|
| Android | ANativeWindow* |
| macOS (OpenGL) | NSView* |
| macOS (Metal) | CAMetalLayer* |
| iOS (OpenGL) | CAEAGLLayer* |
| iOS (Metal) | CAMetalLayer* |
| X11 | Window |
| Windows | HWND |
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
Platform-specific native window handle
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:
// 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
);
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();
}
Platform guides
Platform-specific setup
RenderTarget
Off-screen rendering