• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

visgl / luma.gl / 27877205100

20 Jun 2026 04:32PM UTC coverage: 70.733% (+0.08%) from 70.652%
27877205100

push

github

web-flow
feat(engine) add portable video textures (#2677)

9660 of 15389 branches covered (62.77%)

Branch coverage included in aggregate %.

99 of 116 new or added lines in 2 files covered. (85.34%)

379 existing lines in 28 files now uncovered.

19717 of 26143 relevant lines covered (75.42%)

4107.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

44.25
/modules/webgpu/src/adapter/resources/webgpu-command-encoder.ts
1
// luma.gl
2
// SPDX-License-Identifier: MIT
3
// Copyright (c) vis.gl contributors
4

5
import type {
6
  RenderPassProps,
7
  ComputePassProps,
8
  CopyBufferToTextureOptions,
9
  CopyTextureToTextureOptions,
10
  CopyTextureToBufferOptions
11
} from '@luma.gl/core';
12
import {CommandEncoder, CommandEncoderProps, Buffer} from '@luma.gl/core';
13
import {WebGPUDevice} from '../webgpu-device';
14
import {WebGPUCommandBuffer} from './webgpu-command-buffer';
15
import {WebGPUBuffer} from './webgpu-buffer';
16
import {WebGPURenderPass} from './webgpu-render-pass';
17
import {WebGPUComputePass} from './webgpu-compute-pass';
18
import {WebGPUTexture} from './webgpu-texture';
19
import {WebGPUQuerySet} from './webgpu-query-set';
20

21
export class WebGPUCommandEncoder extends CommandEncoder {
22
  readonly device: WebGPUDevice;
23
  readonly handle: GPUCommandEncoder;
24
  private _transientUploadBuffers: WebGPUBuffer[] = [];
258✔
25

26
  constructor(device: WebGPUDevice, props: CommandEncoderProps = {}) {
258✔
27
    super(device, props);
258✔
28
    this.device = device;
258✔
29
    const suppliedHandle = props.handle as GPUCommandEncoder | undefined;
258✔
30
    this.handle =
258✔
31
      suppliedHandle ||
516✔
32
      this.device.handle.createCommandEncoder({
33
        label: this.props.id
34
        // TODO was this removed in standard?
35
        // measureExecutionTime: this.props.measureExecutionTime
36
      });
37
    this.handle.label = this.props.id;
258✔
38
  }
39

40
  override destroy(): void {
41
    for (const uploadBuffer of this._transientUploadBuffers) {
392✔
42
      uploadBuffer.destroy();
×
43
    }
44
    this._transientUploadBuffers = [];
392✔
45
    this.destroyResource();
392✔
46
  }
47

48
  finish(): WebGPUCommandBuffer {
49
    this.device.pushErrorScope('validation');
199✔
50
    const commandBuffer = new WebGPUCommandBuffer(this, {
199✔
51
      id: this.id,
52
      userData: this.userData
53
    });
54
    this.device.popErrorScope((error: GPUError) => {
199✔
55
      const message = `${this} command encoding: ${error.message}. Maybe add depthWriteEnabled to your Model?`;
×
56
      this.device.reportError(new Error(message), this)();
×
UNCOV
57
      this.device.debug();
×
58
    });
59
    this.destroy();
199✔
60
    return commandBuffer;
199✔
61
  }
62

63
  /** Retains staging uploads until the finished command buffer has been submitted. */
64
  trackTransientUploadBuffer(buffer: WebGPUBuffer): void {
65
    this._transientUploadBuffers.push(buffer);
1✔
66
  }
67

68
  /** Transfers staging-upload ownership to the finished command buffer. */
69
  takeTransientUploadBuffers(): WebGPUBuffer[] {
70
    const transientUploadBuffers = this._transientUploadBuffers;
199✔
71
    this._transientUploadBuffers = [];
199✔
72
    return transientUploadBuffers;
199✔
73
  }
74

75
  /**
76
   * Allows a render pass to begin against a canvas context
77
   * @todo need to support a "Framebuffer" equivalent (aka preconfigured RenderPassDescriptors?).
78
   */
79
  beginRenderPass(props: RenderPassProps = {}): WebGPURenderPass {
81✔
80
    return new WebGPURenderPass(
81✔
81
      this.device,
82
      this._applyTimeProfilingToPassProps(props),
83
      this.handle
84
    );
85
  }
86

87
  beginComputePass(props: ComputePassProps = {}): WebGPUComputePass {
114✔
88
    return new WebGPUComputePass(
114✔
89
      this.device,
90
      this._applyTimeProfilingToPassProps(props),
91
      this.handle
92
    );
93
  }
94

95
  // beginRenderPass(GPURenderPassDescriptor descriptor): GPURenderPassEncoder;
96
  // beginComputePass(optional GPUComputePassDescriptor descriptor = {}): GPUComputePassEncoder;
97

98
  copyBufferToBuffer(options: {
99
    sourceBuffer: Buffer;
100
    sourceOffset?: number;
101
    destinationBuffer: Buffer;
102
    destinationOffset?: number;
103
    size?: number;
104
  }): void {
105
    const webgpuSourceBuffer = options.sourceBuffer as WebGPUBuffer;
5✔
106
    const webgpuDestinationBuffer = options.destinationBuffer as WebGPUBuffer;
5✔
107
    this.handle.copyBufferToBuffer(
5✔
108
      webgpuSourceBuffer.handle,
109
      options.sourceOffset ?? 0,
10✔
110
      webgpuDestinationBuffer.handle,
111
      options.destinationOffset ?? 0,
9✔
112
      options.size ?? 0
5!
113
    );
114
  }
115

116
  copyBufferToTexture(options: CopyBufferToTextureOptions): void {
117
    const webgpuSourceBuffer = options.sourceBuffer as WebGPUBuffer;
×
118
    const webgpuDestinationTexture = options.destinationTexture as WebGPUTexture;
×
119
    const copyOrigin = options.origin ?? [0, 0, 0];
×
120
    const copySize = options.size;
×
UNCOV
121
    this.handle.copyBufferToTexture(
×
122
      {
123
        buffer: webgpuSourceBuffer.handle,
124
        offset: options.byteOffset ?? 0,
×
125
        bytesPerRow: options.bytesPerRow,
126
        rowsPerImage: options.rowsPerImage
127
      },
128
      {
129
        texture: webgpuDestinationTexture.handle,
130
        mipLevel: options.mipLevel ?? 0,
×
131
        origin: {
132
          x: copyOrigin[0] ?? 0,
×
133
          y: copyOrigin[1] ?? 0,
×
134
          z: copyOrigin[2] ?? 0
×
135
        },
136
        aspect: options.aspect
137
      },
138
      {
139
        width: copySize[0],
140
        height: copySize[1],
141
        depthOrArrayLayers: copySize[2]
142
      }
143
    );
144
  }
145

146
  copyTextureToBuffer(options: CopyTextureToBufferOptions): void {
147
    const {
148
      sourceTexture,
149
      destinationBuffer,
150
      origin = [0, 0, 0],
×
151
      byteOffset = 0,
×
152
      width,
153
      height,
154
      depthOrArrayLayers,
155
      mipLevel,
156
      aspect
157
    } = options;
×
158
    const webgpuSourceTexture = sourceTexture as WebGPUTexture;
×
UNCOV
159
    webgpuSourceTexture.copyToBuffer(
×
160
      this.handle,
161
      {
162
        x: origin[0] ?? 0,
×
163
        y: origin[1] ?? 0,
×
164
        z: origin[2] ?? 0,
×
165
        width,
166
        height,
167
        depthOrArrayLayers,
168
        mipLevel,
169
        aspect,
170
        byteOffset,
171
        bytesPerRow: options.bytesPerRow,
172
        rowsPerImage: options.rowsPerImage
173
      },
174
      destinationBuffer
175
    );
176
  }
177

178
  copyTextureToTexture(options: CopyTextureToTextureOptions): void {
179
    const webgpuSourceTexture = options.sourceTexture as WebGPUTexture;
×
180
    const webgpuDestinationTexture = options.destinationTexture as WebGPUTexture;
×
UNCOV
181
    const sourceRegion = webgpuSourceTexture._normalizeTextureReadOptions({
×
182
      x: options.origin?.[0] ?? 0,
×
183
      y: options.origin?.[1] ?? 0,
×
184
      z: options.origin?.[2] ?? 0,
×
185
      width: options.width,
186
      height: options.height,
187
      depthOrArrayLayers: options.depthOrArrayLayers,
188
      mipLevel: options.mipLevel ?? 0,
×
189
      aspect: options.aspect ?? 'all'
×
190
    });
191

UNCOV
192
    this.handle.copyTextureToTexture(
×
193
      {
194
        texture: webgpuSourceTexture.handle,
195
        mipLevel: sourceRegion.mipLevel,
196
        origin: {
197
          x: sourceRegion.x,
198
          y: sourceRegion.y,
199
          z: sourceRegion.z
200
        },
201
        aspect: sourceRegion.aspect
202
      },
203
      {
204
        texture: webgpuDestinationTexture.handle,
205
        mipLevel: options.destinationMipLevel ?? 0,
×
206
        origin: {
207
          x: options.destinationOrigin?.[0] ?? 0,
×
208
          y: options.destinationOrigin?.[1] ?? 0,
×
209
          z: options.destinationOrigin?.[2] ?? 0
×
210
        },
211
        aspect: options.destinationAspect ?? sourceRegion.aspect
×
212
      },
213
      {
214
        width: sourceRegion.width,
215
        height: sourceRegion.height,
216
        depthOrArrayLayers: sourceRegion.depthOrArrayLayers
217
      }
218
    );
219
  }
220

221
  override pushDebugGroup(groupLabel: string): void {
UNCOV
222
    this.handle.pushDebugGroup(groupLabel);
×
223
  }
224

225
  override popDebugGroup(): void {
UNCOV
226
    this.handle.popDebugGroup();
×
227
  }
228

229
  override insertDebugMarker(markerLabel: string): void {
UNCOV
230
    this.handle.insertDebugMarker(markerLabel);
×
231
  }
232

233
  override resolveQuerySet(
234
    querySet: WebGPUQuerySet,
235
    destination: Buffer,
236
    options?: {
237
      firstQuery?: number;
238
      queryCount?: number;
239
      destinationOffset?: number;
240
    }
241
  ): void {
242
    const webgpuQuerySet = querySet;
2✔
243
    const webgpuBuffer = destination as WebGPUBuffer;
2✔
244
    this.handle.resolveQuerySet(
2✔
245
      webgpuQuerySet.handle,
246
      options?.firstQuery || 0,
4✔
247
      options?.queryCount || querySet.props.count - (options?.firstQuery || 0),
8✔
248
      webgpuBuffer.handle,
249
      options?.destinationOffset || 0
4✔
250
    );
251
  }
252

253
  writeTimestamp(querySet: WebGPUQuerySet, queryIndex: number): void {
254
    querySet._invalidateResults();
4✔
255
    const writeTimestamp = (
256
      this.handle as GPUCommandEncoder & {
4✔
257
        writeTimestamp?: (querySet: GPUQuerySet, queryIndex: number) => void;
258
      }
259
    ).writeTimestamp;
260

261
    if (writeTimestamp) {
4!
262
      writeTimestamp.call(this.handle, querySet.handle, queryIndex);
4✔
263
      return;
4✔
264
    }
265

UNCOV
266
    const computePass = this.handle.beginComputePass({
×
267
      timestampWrites: {
268
        querySet: querySet.handle,
269
        beginningOfPassWriteIndex: queryIndex
270
      }
271
    });
UNCOV
272
    computePass.end();
×
273
  }
274
}
275

276
/*
277
  // setDataFromTypedArray(data): this {
278
  //   const textureDataBuffer = this.device.handle.createBuffer({
279
  //     size: data.byteLength,
280
  //     usage: Buffer.COPY_DST | Buffer.COPY_SRC,
281
  //     mappedAtCreation: true
282
  //   });
283
  //   new Uint8Array(textureDataBuffer.getMappedRange()).set(data);
284
  //   textureDataBuffer.unmap();
285

286
  //   this.setBuffer(textureDataBuffer);
287

288
  //   textureDataBuffer.destroy();
289
  //   return this;
290
  // }
291

292
 */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc