• 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

87.01
/modules/engine/src/utils/shader-module-utils.ts
1
// luma.gl
2
// SPDX-License-Identifier: MIT
3
// Copyright (c) vis.gl contributors
4

5
import type {ComputeShaderLayout, ShaderLayout} from '@luma.gl/core';
6
import type {ShaderModule} from '@luma.gl/shadertools';
7

8
type AnyShaderLayout = ShaderLayout | ComputeShaderLayout;
9

10
export function mergeShaderModuleBindingsIntoLayout<TShaderLayout extends AnyShaderLayout>(
11
  shaderLayout: TShaderLayout | null | undefined,
12
  modules: ShaderModule[]
13
): TShaderLayout | null | undefined {
14
  if (!shaderLayout || !modules.some(module => module.bindingLayout?.length)) {
505✔
15
    return shaderLayout;
500✔
16
  }
17

18
  const mergedLayout = {
5✔
19
    ...shaderLayout,
20
    bindings: shaderLayout.bindings.map(binding => ({...binding}))
14✔
21
  } as TShaderLayout;
22

23
  if ('attributes' in (shaderLayout || {})) {
5!
24
    (mergedLayout as ShaderLayout).attributes = (shaderLayout as ShaderLayout)?.attributes || [];
5!
25
  }
26

27
  for (const module of modules) {
5✔
28
    for (const bindingLayout of module.bindingLayout || []) {
6!
29
      for (const relatedBindingName of getRelatedBindingNames(bindingLayout.name)) {
26✔
30
        const binding = mergedLayout.bindings.find(
78✔
31
          candidate => candidate.name === relatedBindingName
167✔
32
        );
33
        if (binding?.group === 0) {
78✔
34
          binding.group = bindingLayout.group;
10✔
35
        }
36
      }
37
    }
38
  }
39

40
  return mergedLayout;
5✔
41
}
42

43
export function mergeInferredShaderLayout(
44
  shaderLayout: ShaderLayout | null | undefined,
45
  inferredShaderLayout: ShaderLayout | null | undefined
46
): ShaderLayout | null | undefined {
47
  if (!shaderLayout) {
36✔
48
    return inferredShaderLayout;
10✔
49
  }
50
  if (!inferredShaderLayout) {
26!
51
    return shaderLayout;
×
52
  }
53

54
  return {
26✔
55
    ...shaderLayout,
56
    attributes: shaderLayout.attributes.length
26✔
57
      ? shaderLayout.attributes
58
      : inferredShaderLayout.attributes,
59
    bindings: mergeBindingLayouts(shaderLayout.bindings, inferredShaderLayout.bindings)
60
  };
61
}
62

63
export function shaderModuleHasUniforms(module: ShaderModule): boolean {
64
  return Boolean(module.uniformTypes && !isObjectEmpty(module.uniformTypes));
500✔
65
}
66

67
export function mergeShaderModules(
68
  explicitModules: ShaderModule[] | undefined,
69
  shaderInputModules: ShaderModule[] | undefined
70
): ShaderModule[] {
71
  const modules: ShaderModule[] = [];
356✔
72
  const moduleNames = new Set<string>();
356✔
73

74
  for (const module of [...(explicitModules || []), ...(shaderInputModules || [])]) {
356!
75
    if (!moduleNames.has(module.name)) {
863✔
76
      moduleNames.add(module.name);
487✔
77
      modules.push(module);
487✔
78
    }
79
  }
80

81
  return modules;
356✔
82
}
83

84
/** Returns binding-name aliases that should share the module-declared bind group. */
85
function getRelatedBindingNames(bindingName: string): string[] {
86
  const bindingNames = new Set<string>([bindingName, `${bindingName}Uniforms`]);
26✔
87

88
  if (!bindingName.endsWith('Uniforms')) {
26!
89
    bindingNames.add(`${bindingName}Sampler`);
26✔
90
  }
91

92
  return [...bindingNames];
26✔
93
}
94

95
function isObjectEmpty(obj: object): boolean {
96
  for (const _key in obj) {
165✔
97
    return false;
165✔
98
  }
UNCOV
99
  return true;
×
100
}
101

102
function mergeBindingLayouts<TBindingLayout extends ShaderLayout['bindings'][number]>(
103
  explicitBindings: TBindingLayout[],
104
  inferredBindings: TBindingLayout[]
105
): TBindingLayout[] {
106
  const mergedBindings = explicitBindings.map(binding => ({...binding}));
26✔
107
  const explicitBindingNames = new Set(explicitBindings.map(binding => binding.name));
26✔
108
  const explicitBindingLocations = new Set(
26✔
109
    explicitBindings.map(binding => `${binding.group}:${binding.location}`)
3✔
110
  );
111

112
  for (const inferredBinding of inferredBindings) {
26✔
113
    const inferredBindingLocation = `${inferredBinding.group}:${inferredBinding.location}`;
236✔
114
    if (
236✔
115
      !explicitBindingNames.has(inferredBinding.name) &&
469✔
116
      !explicitBindingLocations.has(inferredBindingLocation)
117
    ) {
118
      mergedBindings.push({...inferredBinding});
233✔
119
    }
120
  }
121

122
  return mergedBindings;
26✔
123
}
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