Skip to content

[ui] Graph canvas is black on high-DPI/large displays: EffectComposer MSAA render target exceeds GPU allocation (glRenderbufferStorageMultisample too large) due to uncapped setPixelRatio(dpr) #648

Description

@AndreLFSMartins

Version

codebase-memory-mcp 0.8.1 (darwin-arm64, ui variant)

Platform

macOS 26.5.1 (Apple M5 Pro), Brave + Chrome. Reproduces on any Chromium browser when the window is large / on a high-DPI display.

What happened

Clicking View Graph shows the Graph tab with the correct sidebar, filters, and node/edge counts (e.g. 2,648 nodes / 5,095 edges), but the 3D canvas is entirely black. No UI error, ErrorBoundary does not trigger. Same black-canvas symptom as the (closed) #453, but a different root cause — see below.

Root cause (confirmed via chrome://gpu log)

The post-processing pipeline (EffectComposer + RenderPass, present in the served bundle) creates a multisampled render target sized to the canvas backing store, which is cssSize × devicePixelRatio. The bundle calls renderer.setPixelRatio(dpr) with the uncapped device DPR. On a large, high-DPI display the multisampled renderbuffer exceeds the GPU's max allocation:

GL_INVALID_OPERATION: glRenderbufferStorageMultisample: Texture total allocation size is too large.
GL_INVALID_FRAMEBUFFER_OPERATION: glClear: Framebuffer is incomplete: Attachment has zero size.
GL_INVALID_FRAMEBUFFER_OPERATION: glDrawElementsInstanced: Framebuffer is incomplete: Attachment has zero size.

Because the MSAA renderbuffer allocation fails, the composer's framebuffer attachment ends up zero-sized, every subsequent glClear/glDrawElementsInstanced/glBlitFramebuffer targets an incomplete framebuffer, and nothing is drawn → black canvas. The MCP server, the data, and plain WebGL2 are all fine (a WebGL1 test page renders a cube normally).

GPU context from the log:

  • GL_RENDERER: ANGLE (Apple, ANGLE Metal Renderer: Apple M5 Pro)
  • Max. MSAA samples: 8
  • Displays: internal 1800x1169 @ scale 2, external 2560x1440 @ scale 2, external 3200x1800 @ scale 2

Reproduction

  1. Index any repo and open the graph UI on a high-DPI display (devicePixelRatio = 2).
  2. Maximize the browser window on a large/high-res monitor.
  3. Click View Graph → black canvas; chrome://gpu Log Messages show glRenderbufferStorageMultisample: Texture total allocation size is too large.
  4. Workaround that confirms the cause: shrink the window (or Cmd - zoom out, or move to a lower-res display) and reload → the graph renders. This proves it is the canvas/render-target size, not Shields/CDN/data.

Suggested fix

Cap the renderer pixel ratio for the WebGL canvas / composer, e.g.:

renderer.setPixelRatio(Math.min(window.devicePixelRatio, 1.5))

or, more robustly, clamp the composer's render-target dimensions to gl.getParameter(gl.MAX_RENDERBUFFER_SIZE) (and to a sane total-bytes budget), and/or fall back to antialias: false / samples: 0 on the composer when the would-be allocation exceeds the limit. R3F's <Canvas dpr={[1, 1.5]}> is the one-line equivalent.

Bonus: when glRenderbufferStorageMultisample fails, surface it through the ErrorBoundary instead of silently rendering black.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.stability/performanceServer crashes, OOM, hangs, high CPU/memoryux/behaviorDisplay bugs, docs, adoption UX

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions