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

visgl / luma.gl / 16849865984

09 Aug 2025 01:25PM UTC coverage: 73.868% (-0.5%) from 74.38%
16849865984

push

github

web-flow
feat(webgpu): Read pixels (#2415)

2063 of 2704 branches covered (76.29%)

Branch coverage included in aggregate %.

411 of 626 new or added lines in 9 files covered. (65.65%)

130 existing lines in 11 files now uncovered.

27064 of 36727 relevant lines covered (73.69%)

46.56 hits per line

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

58.2
/modules/core/src/portable/uniform-buffer-layout.ts
1
// luma.gl
1✔
2
// SPDX-License-Identifier: MIT
1✔
3
// Copyright (c) vis.gl contributors
1✔
4

1✔
5
import type {PrimitiveDataType} from '../shadertypes/data-types/data-types';
1✔
6
import type {VariableShaderType} from '../shadertypes/data-types/shader-types';
1✔
7
import {alignTo} from '../shadertypes/data-types/decode-data-types';
1✔
8
import {getVariableShaderTypeInfo} from '../shadertypes/data-types/decode-shader-types';
1✔
9

1✔
10
import type {UniformValue} from '../adapter/types/uniforms';
1✔
11
import {getScratchArrayBuffer} from '../utils/array-utils-flat';
1✔
12
import {isNumberArray} from '../utils/is-array';
1✔
13
import {log} from '../utils/log';
1✔
14

1✔
15
/**
1✔
16
 * Smallest buffer size that can be used for uniform buffers.
1✔
17
 * TODO - does this depend on device?
1✔
18
 */
1✔
19
const minBufferSize: number = 1024;
1✔
20

1✔
21
/**
1✔
22
 * Std140 layout for uniform buffers
1✔
23
 * Supports manual listing of uniforms
1✔
24
 */
1✔
25
export class UniformBufferLayout {
1✔
26
  readonly layout: Record<string, {offset: number; size: number; type: PrimitiveDataType}> = {};
9✔
27

9✔
28
  /** number of bytes needed for buffer allocation */
9✔
29
  readonly byteLength: number;
9✔
30

9✔
31
  /** Create a new UniformBufferLayout given a map of attributes. */
9✔
32
  constructor(
9✔
33
    uniformTypes: Record<string, VariableShaderType>,
9✔
34
    uniformSizes: Record<string, number> = {}
9✔
35
  ) {
9✔
36
    /** number of 4 byte slots taken */
9✔
37
    let size: number = 0;
9✔
38

9✔
39
    // Add layout (type, size and offset) definitions for each uniform in the layout
9✔
40
    for (const [key, uniformType] of Object.entries(uniformTypes)) {
9✔
41
      const typeAndComponents = getVariableShaderTypeInfo(uniformType);
114✔
42
      const {type, components} = typeAndComponents;
114✔
43
      // Calculate total count for uniform arrays.
114✔
44
      const count = components * (uniformSizes?.[key] ?? 1);
114✔
45
      // First, align (bump) current offset to an even multiple of current object (1, 2, 4)
114✔
46
      size = alignTo(size, count);
114✔
47
      // Use the aligned size as the offset of the current uniform.
114✔
48
      const offset = size;
114✔
49
      // Then, add our object's padded size ((1, 2, multiple of 4) to the current offset
114✔
50
      size += count;
114✔
51
      this.layout[key] = {type, size: count, offset};
114✔
52
    }
114✔
53
    size += (4 - (size % 4)) % 4;
9✔
54

9✔
55
    const actualByteLength = size * 4;
9✔
56
    this.byteLength = Math.max(actualByteLength, minBufferSize);
9✔
57
  }
9✔
58

9✔
59
  /** Get the data for the complete buffer */
9✔
60
  getData(uniformValues: Record<string, UniformValue>): Uint8Array {
9✔
UNCOV
61
    // Allocate three typed arrays pointing at same memory
×
UNCOV
62
    const arrayBuffer = getScratchArrayBuffer(this.byteLength);
×
UNCOV
63
    const typedArrays = {
×
UNCOV
64
      i32: new Int32Array(arrayBuffer),
×
UNCOV
65
      u32: new Uint32Array(arrayBuffer),
×
UNCOV
66
      f32: new Float32Array(arrayBuffer),
×
UNCOV
67
      // TODO not implemented
×
UNCOV
68
      f16: new Uint16Array(arrayBuffer)
×
UNCOV
69
    };
×
UNCOV
70

×
UNCOV
71
    for (const [name, value] of Object.entries(uniformValues)) {
×
UNCOV
72
      const uniformLayout = this.layout[name];
×
UNCOV
73
      if (!uniformLayout) {
×
74
        log.warn(`Supplied uniform value ${name} not present in uniform block layout`)();
×
75
        // eslint-disable-next-line no-continue
×
76
        continue;
×
77
      }
×
UNCOV
78

×
UNCOV
79
      const {type, size, offset} = uniformLayout;
×
UNCOV
80
      const typedArray = typedArrays[type];
×
UNCOV
81
      if (size === 1) {
×
UNCOV
82
        if (typeof value !== 'number' && typeof value !== 'boolean') {
×
83
          log.warn(
×
84
            `Supplied value for single component uniform ${name} is not a number: ${value}`
×
85
          )();
×
86
          // eslint-disable-next-line no-continue
×
87
          continue;
×
88
        }
×
UNCOV
89
        // single value -> just set it
×
UNCOV
90
        typedArray[offset] = Number(value);
×
UNCOV
91
      } else {
×
92
        if (!isNumberArray(value)) {
×
93
          log.warn(
×
94
            `Supplied value for multi component / array uniform ${name} is not a numeric array: ${value}`
×
95
          )();
×
96
          // eslint-disable-next-line no-continue
×
97
          continue;
×
98
        }
×
99
        // vector/matrix -> copy the supplied (typed) array, starting from offset
×
100
        // TODO: we should limit or check size in case the supplied data overflows
×
101
        typedArray.set(value, offset);
×
102
      }
×
UNCOV
103
    }
×
UNCOV
104

×
UNCOV
105
    return new Uint8Array(arrayBuffer, 0, this.byteLength);
×
UNCOV
106
  }
×
107

9✔
108
  /** Does this layout have a field with specified name */
9✔
109
  has(name: string) {
9✔
110
    return Boolean(this.layout[name]);
×
111
  }
×
112

9✔
113
  /** Get offset and size for a field with specified name */
9✔
114
  get(name: string): {offset: number; size: number} | undefined {
9✔
115
    const layout = this.layout[name];
×
116
    return layout;
×
117
  }
×
118
}
9✔
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