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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions