Start · Sprachen · JavaScript · Referenz · GPUTexture.sampleCount

GPUTexture.sampleCount

Eigenschaft

Schreibgeschützte Eigenschaft, die angibt, wie viele Samples pro Texel eine <code>GPUTexture</code> hat – <code>1</code> für normale Texturen, <code>4</code> für Multisampling (MSAA).

seit JavaScript WebGPU: Chrome/Edge 113+, Safari 26+, Firefox 141+ Kategorie: webapi

Signatur

GPUTexture.sampleCount

Beschreibung

Die Eigenschaft sampleCount einer GPUTexture gibt die Anzahl der Samples pro Texel zurück. Der Wert entspricht dem Feld sampleCount des Deskriptors, der beim Erzeugen der Textur an GPUDevice.createTexture() übergeben wurde. Fehlt das Feld dort, ist der Standardwert 1.

Wichtig ist der Wert beim Multisample-Anti-Aliasing (MSAA). Eine Textur mit sampleCount: 4 speichert pro Pixel vier Farb- bzw. Tiefenwerte. Nach dem Rendern werden diese über ein resolveTarget in eine normale Textur mit einem Sample zusammengeführt. WebGPU erlaubt derzeit nur die Werte 1 und 4.

Nützlich ist die Eigenschaft vor allem in generischem Code, etwa in Render-Graphen, Hilfsfunktionen oder Debug-Werkzeugen. Dort kommen Texturen oft von außen, und man muss prüfen, ob sie zu einer Pipeline passen. Der multisample.count der Render-Pipeline muss nämlich mit dem sampleCount aller Farb- und Tiefen-Anhänge im Render-Pass übereinstimmen.

Rückgabewert

Typ
number
Beschreibung
Eine ganze Zahl ohne Vorzeichen (GPUSize32Out): 1 bei einer normalen Textur, 4 bei einer Multisample-Textur.

Beispiele

sampleCount einer normalen und einer MSAA-Textur auslesen

const adapter = await navigator.gpu?.requestAdapter();
if (!adapter) throw new Error('WebGPU nicht verfügbar');
const device = await adapter.requestDevice();

const normal = device.createTexture({
  size: [256, 256],
  format: 'rgba8unorm',
  usage: GPUTextureUsage.TEXTURE_BINDING
});

const msaa = device.createTexture({
  size: [256, 256],
  format: 'rgba8unorm',
  sampleCount: 4,
  usage: GPUTextureUsage.RENDER_ATTACHMENT
});

console.log(normal.sampleCount);
console.log(msaa.sampleCount);
1 4

MSAA-Render-Pass mit passender Pipeline und Resolve-Ziel

const canvas = document.querySelector('canvas');
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const context = canvas.getContext('webgpu');
const format = navigator.gpu.getPreferredCanvasFormat();
context.configure({ device, format });

const msaaTexture = device.createTexture({
  size: [canvas.width, canvas.height],
  format,
  sampleCount: 4,
  usage: GPUTextureUsage.RENDER_ATTACHMENT
});

const module = device.createShaderModule({ code: `
  @vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {
    var p = array(vec2f(0, 0.5), vec2f(-0.5, -0.5), vec2f(0.5, -0.5));
    return vec4f(p[i], 0, 1);
  }
  @fragment fn fs() -> @location(0) vec4f { return vec4f(1, 0.4, 0, 1); }
`});

// Die Pipeline übernimmt den sampleCount der Textur
const pipeline = device.createRenderPipeline({
  layout: 'auto',
  vertex: { module, entryPoint: 'vs' },
  fragment: { module, entryPoint: 'fs', targets: [{ format }] },
  multisample: { count: msaaTexture.sampleCount }
});

const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({
  colorAttachments: [{
    view: msaaTexture.createView(),
    resolveTarget: context.getCurrentTexture().createView(),
    loadOp: 'clear',
    clearValue: [0, 0, 0, 1],
    storeOp: 'discard'
  }]
});
pass.setPipeline(pipeline);
pass.draw(3);
pass.end();
device.queue.submit([encoder.finish()]);

Hilfsfunktion: Anhänge vor dem Render-Pass prüfen

const assertMatchingSamples = (pipelineCount, ...textures) => {
  for (const tex of textures) {
    if (tex.sampleCount !== pipelineCount) {
      throw new Error(
        `Textur "${tex.label}" hat sampleCount ${tex.sampleCount}, Pipeline erwartet ${pipelineCount}`
      );
    }
  }
};

const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();

const color = device.createTexture({
  label: 'Farbe', size: [640, 480], format: 'rgba8unorm',
  sampleCount: 4, usage: GPUTextureUsage.RENDER_ATTACHMENT
});
const depth = device.createTexture({
  label: 'Tiefe', size: [640, 480], format: 'depth24plus',
  usage: GPUTextureUsage.RENDER_ATTACHMENT // sampleCount fehlt → 1
});

try {
  assertMatchingSamples(4, color, depth);
} catch (e) {
  console.warn(e.message);
}
Textur "Tiefe" hat sampleCount 1, Pipeline erwartet 4

// Wichtig · Fallstricke

  • Schreibgeschützt: Den Wert kann man nach dem Erzeugen nicht mehr ändern. Eine Zuweisung wird ignoriert bzw. löst im Strict Mode einen TypeError aus. Wer einen anderen Wert braucht, muss eine neue Textur anlegen.
  • Nur 1 oder 4: Andere Werte wie 2 oder 8 führen bei createTexture() zu einem Validierungsfehler. Außerdem muss das Format Multisampling unterstützen. Einige Formate, etwa viele r32float-Varianten, können ohne zusätzliches Feature nicht aufgelöst werden.
  • Einschränkungen bei Multisample-Texturen: Sie müssen dimension: '2d', mipLevelCount: 1 und ein RENDER_ATTACHMENT-Usage haben. STORAGE_BINDING ist nicht erlaubt. In WGSL liest man sie als texture_multisampled_2d.
  • Canvas-Texturen: Die Textur von context.getCurrentTexture() hat immer sampleCount 1. Für MSAA braucht man deshalb eine eigene Multisample-Textur, die per resolveTarget in die Canvas-Textur aufgelöst wird.
  • Speicher: Eine Textur mit 4 Samples belegt ungefähr viermal so viel Grafikspeicher. storeOp: 'discard' auf der MSAA-Textur kann auf Tile-basierten GPUs Bandbreite sparen.
  • Kompatibilität: WebGPU gibt es nur in sicheren Kontexten und noch nicht überall. Die Unterstützung sollte man mit navigator.gpu und requestAdapter() prüfen.