Skip to content

[Bug] Linux guest: virgl reports 32 texture image units, but shaders using more than 16 samplers fail on the host #41

Description

@janah01

Description

In a Linux guest with GPU acceleration on, WebGL2 on the guest's GL driver (virgl) reports MAX_TEXTURE_IMAGE_UNITS = 32, but any fragment shader that uses more than 16 samplers fails on the host. The guest gets no GL error and no context loss: the draw silently produces nothing, and the kernel logs virtio_gpu errors. Programs that size their shaders from the reported limit therefore render nothing, and one that redraws every frame can leave its whole window blank.

Steps to Reproduce

  1. Create an Ubuntu 26.04 ARM64 VM with GPU acceleration enabled.
  2. In any Chromium-based browser or app in the guest, open DevTools and run the snippet below, changing the final (17) to (16) to compare.
  3. Watch sudo dmesg -w in the guest while it runs.
(N => {
  const gl = document.createElement('canvas').getContext('webgl2');
  const sh = (t, s) => { const x = gl.createShader(t); gl.shaderSource(x, s); gl.compileShader(x); return x; };
  let chain = ''; for (let i = 1; i < N; i++) chain += ` else if (page == ${i}) o = texture(tex[${i}], vec2(0.5));`;
  const p = gl.createProgram();
  gl.attachShader(p, sh(gl.VERTEX_SHADER, `#version 300 es
    layout(location=0) in vec2 a; void main(){ gl_Position = vec4(a, 0.0, 1.0); }`));
  gl.attachShader(p, sh(gl.FRAGMENT_SHADER, `#version 300 es
    precision lowp float; uniform int page; uniform sampler2D tex[${N}]; out vec4 o;
    void main(){ if (page == 0) o = texture(tex[0], vec2(0.5));${chain} }`));
  gl.linkProgram(p); gl.useProgram(p);
  gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);
  gl.enableVertexAttribArray(0); gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
  for (let i = 0; i < N; i++) {
    gl.activeTexture(gl.TEXTURE0 + i); gl.bindTexture(gl.TEXTURE_2D, gl.createTexture());
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255, 0, 0, 255]));
  }
  gl.uniform1iv(gl.getUniformLocation(p, 'tex'), Int32Array.from({length: N}, (_, i) => i));
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
  const px = new Uint8Array(4); gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, px);
  return {maxUnits: gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS), linked: gl.getProgramParameter(p, gl.LINK_STATUS),
          glError: gl.getError(), lost: gl.isContextLost(), pixel: [...px]};
})(17)

Current Behavior

Samplers in shader Pixel read back Guest GL error / context lost virtio_gpu kernel errors
8 [255, 0, 0, 255] none / no 0
16 [255, 0, 0, 255] none / no 0
17 [0, 0, 0, 0] none / no 5–6
32 [0, 0, 0, 0] none / no 4–6

MAX_TEXTURE_IMAGE_UNITS is reported as 32 in every case, and the program links successfully in the guest. Each failing draw logs:

[drm:virtio_gpu_dequeue_ctrl_func [virtio_gpu]] *ERROR* response 0x1200 (command 0x207)

That is VIRTIO_GPU_RESP_ERR_UNSPEC in answer to VIRTIO_GPU_CMD_SUBMIT_3D.

Draws, instanced draws, texture uploads and mipmap generation with 16 or fewer samplers all work without errors.

Expected Behavior

Either the guest should report the limit the host can actually honour (16), or shaders using up to the reported 32 samplers should work. Failures should surface to the guest as a GL error or link failure rather than silently dropping the draw.

Environment

  • App version: VMPal 0.67 (67)
  • Mac: Apple M5 Pro
  • macOS version: macOS 27.0.1 (26A434)
  • VM's OS: Ubuntu 26.04.1 LTS (ARM64), kernel 7.0.0-38-generic, Mesa 26.0.8, GNOME on Wayland
  • GL renderer in guest: ANGLE (Mesa, virgl (Apple M5 Pro), OpenGL ES 3.0)
  • Kernel: virtio_gpu features +virgl +edid -resource_blob -host_visible -context_init

Log

No crash; the VM keeps running. Kernel message as above.

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 working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions