Start · Sprachen · JavaScript · Referenz · GPUTexture

GPUTexture

Schnittstelle

Ein <code>GPUTexture</code> ist ein GPU-Speicherbereich für 1D-, 2D- oder 3D-Datenarrays wie Bilder, Render-Ziele oder Tiefenpuffer, die in WebGPU-Render- und Compute-Durchläufen genutzt werden.

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

Signatur

interface GPUTexture

Beschreibung

GPUTexture ist ein zentrales Ressourcen-Objekt der WebGPU API. Eine Textur enthält formatierte Texel-Daten (z. B. rgba8unorm, depth24plus) und kann als Bildquelle für Shader, als Farb- oder Tiefenziel eines Render-Durchlaufs oder als Speicher-Textur (storage texture) in Compute-Shadern dienen. Du erstellst sie nicht mit einem Konstruktor, sondern über GPUDevice.createTexture(descriptor). Die Textur des Canvas bekommst du bei jedem Frame über GPUCanvasContext.getCurrentTexture().

Shader greifen nie direkt auf eine Textur zu, sondern immer über eine Ansicht (GPUTextureView), die du mit createView() erzeugst. Eine Ansicht kann einen Teilbereich auswählen (Mip-Level, Array-Layer, Aspekt) oder die Daten anders interpretieren, z. B. als cube- oder 2d-array-Ansicht.

Alle Eigenschaften sind schreibgeschützt und spiegeln den Deskriptor wider, mit dem die Textur erstellt wurde:

  • width, height, depthOrArrayLayers – Abmessungen
  • format – Texelformat (GPUTextureFormat)
  • dimension – "1d", "2d" oder "3d"
  • mipLevelCount, sampleCount – Anzahl der Mip-Stufen bzw. Multisampling-Samples
  • usage – Bitmaske aus GPUTextureUsage-Flags
  • label – frei wählbarer Name für Fehlermeldungen und Debugging (beschreibbar)

Methoden: createView(descriptor?) erzeugt eine GPUTextureView, destroy() gibt den GPU-Speicher sofort frei. Daten überträgst du mit GPUQueue.writeTexture(), GPUQueue.copyExternalImageToTexture() oder mit Kopierbefehlen des GPUCommandEncoder.

Parameter

Name Typ Default Beschreibung
$descriptor.size Pflicht GPUExtent3D ([w, h?, d?] | {width, height?, depthOrArrayLayers?}) Abmessungen der Textur; wird an device.createTexture() übergeben.
$descriptor.format Pflicht GPUTextureFormat Texelformat, z. B. "rgba8unorm", "bgra8unorm", "depth24plus".
$descriptor.usage Pflicht number (GPUTextureUsage-Flags) Bitmaske aus COPY_SRC, COPY_DST, TEXTURE_BINDING, STORAGE_BINDING, RENDER_ATTACHMENT.
$descriptor.dimension "1d" | "2d" | "3d" "2d" Dimensionalität der Textur.
$descriptor.mipLevelCount number 1 Anzahl der Mip-Stufen.
$descriptor.sampleCount number 1 Samples pro Texel; 4 für Multisampling (MSAA).
$descriptor.viewFormats GPUTextureFormat[] [] Zusätzliche Formate, die für createView() erlaubt sind (z. B. die sRGB-Variante).
$descriptor.label string "" Name für Debugging und Fehlermeldungen.

Rückgabewert

Typ
GPUTexture
Beschreibung
device.createTexture(descriptor) gibt ein neues GPUTexture-Objekt zurück. Bei ungültigem Deskriptor entsteht ein ungültiges Objekt, und es wird ein Validierungsfehler gemeldet – es wird keine Ausnahme geworfen.

Beispiele

Textur erstellen und Eigenschaften lesen

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

const texture = device.createTexture({
  label: 'Sprite-Atlas',
  size: [512, 256],
  format: 'rgba8unorm',
  usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST
});

console.log(texture.width, texture.height, texture.format, texture.dimension);
console.log((texture.usage & GPUTextureUsage.COPY_DST) !== 0);
512 256 rgba8unorm 2d true

Bild in eine Textur laden und für Shader binden

const loadTexture = async (device, url) => {
  const blob = await (await fetch(url)).blob();
  const bitmap = await createImageBitmap(blob, { colorSpaceConversion: 'none' });

  const texture = device.createTexture({
    label: url,
    size: [bitmap.width, bitmap.height],
    format: 'rgba8unorm',
    usage: GPUTextureUsage.TEXTURE_BINDING |
           GPUTextureUsage.COPY_DST |
           GPUTextureUsage.RENDER_ATTACHMENT // für copyExternalImageToTexture nötig
  });

  device.queue.copyExternalImageToTexture(
    { source: bitmap },
    { texture },
    [bitmap.width, bitmap.height]
  );
  bitmap.close();
  return texture;
};

const texture = await loadTexture(device, '/img/holz.png');
const sampler = device.createSampler({ magFilter: 'linear', minFilter: 'linear' });

// pipeline wurde vorher mit layout: 'auto' erstellt
const bindGroup = device.createBindGroup({
  layout: pipeline.getBindGroupLayout(0),
  entries: [
    { binding: 0, resource: sampler },
    { binding: 1, resource: texture.createView() }
  ]
});

Tiefenpuffer passend zum Canvas und Freigabe bei Größenänderung

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

let depthTexture = null;

const ensureDepthTexture = () => {
  if (depthTexture &&
      depthTexture.width === canvas.width &&
      depthTexture.height === canvas.height) return depthTexture;
  depthTexture?.destroy(); // alten GPU-Speicher sofort freigeben
  depthTexture = device.createTexture({
    label: 'Tiefenpuffer',
    size: [canvas.width, canvas.height],
    format: 'depth24plus',
    usage: GPUTextureUsage.RENDER_ATTACHMENT
  });
  return depthTexture;
};

const frame = () => {
  const encoder = device.createCommandEncoder();
  const pass = encoder.beginRenderPass({
    colorAttachments: [{
      view: context.getCurrentTexture().createView(),
      clearValue: { r: 0.1, g: 0.1, b: 0.15, a: 1 },
      loadOp: 'clear',
      storeOp: 'store'
    }],
    depthStencilAttachment: {
      view: ensureDepthTexture().createView(),
      depthClearValue: 1,
      depthLoadOp: 'clear',
      depthStoreOp: 'store'
    }
  });
  pass.end();
  device.queue.submit([encoder.finish()]);
  requestAnimationFrame(frame);
};
requestAnimationFrame(frame);