Using PGraphics in Processing for Off‑Screen Drawing and Caching
Learn how to create and reuse a PGraphics buffer in Processing to cache complex drawings and keep frame rates high.
24 Jul 2025, 04:06 UTC

Why use PGraphics
When a sketch redraws the same complex graphics every frame, the CPU or GPU spends time re‑executing drawing commands that have not changed. PGraphics creates an off‑screen render target that you can draw to once, then reuse the resulting image each frame. This reduces per‑frame work and keeps the frame rate high.
Basic workflow
- Create a PGraphics object with
createGraphics(width, height, renderer). The renderer should match the main sketch’s renderer (e.g.,P2DorP3D). - In
draw(), callpg.beginDraw(), issue the drawing commands you want to cache, then callpg.endDraw(). Forgetting either call leaves the buffer locked and can cause visual artifacts or crashes. - Draw the cached buffer to the screen with
image(pg, x, y)(or any variant).
Example: caching a complex background
The following sketch draws a detailed vector pattern once to a PGraphics buffer and reuses it each frame.
// Settings must match the main sketch’s renderer
PGraphics bg;
void setup() {
size(800, 600, P2D); // main sketch uses P2D
bg = createGraphics(width, height, P2D);
// Draw the static content once
bg.beginDraw();
bg.background(30);
bg.noFill();
bg.stroke(200, 100, 0);
for (int i = 0; i < 200; i++) {
float x = random(width);
float y = random(height);
float size = random(10, 50);
bg.ellipse(x, y, size, size);
}
bg.endDraw();
}
void draw() {
// Reuse the cached background
image(bg, 0, 0);
// Draw dynamic content on top
fill(255, 100);
noStroke();
ellipse(mouseX, mouseY, 80, 80);
}
Run this example in the Processing IDE. The frame rate should stay high because the expensive ellipse loop executes only once during setup(). The moving circle is drawn each frame on top of the cached background.
Limits and common mistakes
- Memory consumption: Each PGraphics allocates memory proportional to its width × height × pixel size. Large buffers can exhaust available RAM or GPU memory. Monitor memory with VisualVM or Processing’s built‑in profiler; usage should stabilize after creation.
- Renderer mismatch: If you create the PGraphics with a different renderer than the main sketch (e.g., main sketch uses
P3Dbut PGraphics usesJAVA2D), some drawing commands may be ignored or throw exceptions. Always pass the same renderer string tocreateGraphics. - Frequent recreation: Calling
createGraphicsinsidedraw()forces a new buffer each frame, causing stalls and defeating the purpose. Create the PGraphics once insetup()(or when the size truly changes). - Drawing after dispose: Calling
pg.dispose()frees the buffer’s native resources. Any subsequentbeginDraw(), drawing commands, orimage(pg, …)will throw aNullPointerException. Dispose only when you are done with the buffer for the rest of the sketch. - Off‑screen shader differences: Some shader uniforms or texture lookups behave differently when rendered to a PGraphics versus the main canvas. Test shader effects in both contexts if you rely on them.
Verification tips
- Compare the cached result to a direct on‑screen draw: use
pg.get()to copy the buffer into a pixel array and draw those pixels withset()orimage()to ensure visual equivalence. - Enable the frame rate display (
frameRate) and observe that it remains steady when the complex content is cached versus when it is redrawn each frame. - If you suspect memory issues, run the sketch with VisualVM attached and watch the heap size; it should rise once at PGraphics creation and then stay flat.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.