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

visgl / luma.gl / 28704923726

04 Jul 2026 11:35AM UTC coverage: 72.256% (+0.07%) from 72.186%
28704923726

Pull #2732

github

web-flow
Merge b794abe43 into 30d8c7ace
Pull Request #2732: [codex] Simplify text rendering behind TextRenderer

11260 of 17561 branches covered (64.12%)

Branch coverage included in aggregate %.

361 of 495 new or added lines in 17 files covered. (72.93%)

12 existing lines in 4 files now uncovered.

21829 of 28233 relevant lines covered (77.32%)

5613.38 hits per line

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

83.33
/modules/text/src/text-2d/gpu-text-data.ts
1
// luma.gl
2
// SPDX-License-Identifier: MIT
3
// Copyright (c) vis.gl contributors
4

5
import type {TextAttributeRenderProps, TextAttributeState} from './models/text-attribute-model';
6
import type {TextStorageRenderProps} from './models/text-storage-model';
7
import type {TextDictionaryRenderProps} from './models/text-dictionary-model';
8
import type {TextDictionaryState, TextStorageState} from './model-utils/text-storage-state';
9
import type {GPUTextResources} from './gpu-text-resources';
10

11
/** Prepared text representation selected by an adapter or forced through the experimental API. */
12
export type GPUTextStrategy = 'attribute' | 'storage' | 'storage-row-indexed' | 'dictionary';
13

14
/** Representation-independent preparation and memory statistics for {@link GPUTextData}. */
15
export type GPUTextStats = {
16
  /** Strategy used to prepare and render the data. */
17
  strategy: GPUTextStrategy;
18
  /** Number of source text rows. */
19
  rowCount: number;
20
  /** Number of visible glyph instances generated from all source rows. */
21
  glyphCount: number;
22
  /** Number of preserved source batches or chunks. */
23
  sourceBatchCount: number;
24
  /** Number of draw batches after applying device buffer-size limits. */
25
  renderBatchCount: number;
26
  /** CPU preparation time in milliseconds. */
27
  preparationTimeMs: number;
28
  /** Bytes retained by prepared glyph, row, atlas-definition, and control data. */
29
  retainedByteLength: number;
30
  /** Bytes used by temporary compute inputs that are released after preparation. */
31
  transientByteLength: number;
32
};
33

34
type GPUTextAttributeData = {
35
  strategy: 'attribute';
36
  modelProps: TextAttributeRenderProps;
37
  state: TextAttributeState;
38
};
39

40
type GPUTextStorageData = {
41
  strategy: 'storage' | 'storage-row-indexed';
42
  modelProps: TextStorageRenderProps;
43
  state: TextStorageState;
44
};
45

46
type GPUTextDictionaryData = {
47
  strategy: 'dictionary';
48
  modelProps: TextDictionaryRenderProps;
49
  state: TextDictionaryState;
50
};
51

52
/** @internal Strategy-specific prepared data accepted by the experimental factory. */
53
export type GPUTextDataProps = GPUTextAttributeData | GPUTextStorageData | GPUTextDictionaryData;
54

55
/**
56
 * Caller-owned prepared text data shared by render and picking models.
57
 *
58
 * The public surface intentionally exposes only representation-independent counts, statistics,
59
 * and destruction. Strategy-specific state is available only through the experimental entry
60
 * point. Destroy every borrowing renderer before destroying its data.
61
 */
62
export interface GPUTextData {
63
  /** Shared atlas resources borrowed by this batch. */
64
  readonly resources: GPUTextResources;
65
  /** Strategy selected while preparing this data. */
66
  readonly strategy: GPUTextStrategy;
67
  /** Source stream batch index. */
68
  readonly sourceBatchIndex: number;
69
  /** Global source-row index assigned to local row zero. */
70
  readonly rowIndexBase: number;
71
  /** Global glyph index assigned to local glyph zero. */
72
  readonly glyphIndexBase: number;
73
  /** Number of source text rows in this batch. */
74
  readonly rowCount: number;
75
  /** Number of visible glyph instances in this batch. */
76
  readonly glyphCount: number;
77
  /** Compact representation-independent preparation statistics. */
78
  readonly stats: GPUTextStats;
79
  /** Releases the owned source batch, generated buffers, and tables. Idempotent. */
80
  destroy(): void;
81
}
82

83
/** @internal */
84
export class GPUTextDataImpl implements GPUTextData {
85
  readonly resources: GPUTextResources;
86
  readonly strategy: GPUTextStrategy;
87
  readonly sourceBatchIndex: number;
88
  readonly rowIndexBase: number;
89
  readonly glyphIndexBase: number;
90
  readonly rowCount: number;
91
  readonly glyphCount: number;
92
  readonly stats: GPUTextStats;
93
  private readonly props: GPUTextDataProps;
94
  private readonly destroySource?: () => void;
95
  private destroyed = false;
15✔
96

97
  constructor(
98
    props: GPUTextDataProps,
99
    options: {
100
      resources: GPUTextResources;
101
      sourceBatchIndex: number;
102
      rowIndexBase: number;
103
      glyphIndexBase: number;
104
      rowCount: number;
105
      destroySource?: () => void;
106
    }
107
  ) {
108
    this.props = props;
15✔
109
    this.resources = options.resources;
15✔
110
    this.strategy = props.strategy;
15✔
111
    this.sourceBatchIndex = options.sourceBatchIndex;
15✔
112
    this.rowIndexBase = options.rowIndexBase;
15✔
113
    this.glyphIndexBase = options.glyphIndexBase;
15✔
114
    this.rowCount = options.rowCount;
15✔
115
    this.destroySource = options.destroySource;
15✔
116
    this.glyphCount =
15✔
117
      props.strategy === 'attribute' ? props.state.glyphLayout.glyphCount : props.state.glyphCount;
15!
118
    this.stats = makeGPUTextStats(props, options.rowCount);
15✔
119
  }
120

121
  /** Releases all prepared and source resources owned by this data object exactly once. */
122
  destroy(): void {
123
    if (this.destroyed) {
16✔
124
      return;
1✔
125
    }
126
    this.destroyed = true;
15✔
127
    destroyGPUTextState(this.props);
15✔
128
    this.destroySource?.();
15✔
129
  }
130

131
  getInternalProps(): GPUTextDataProps {
132
    return this.props;
13✔
133
  }
134
}
135

136
/** @internal */
137
export function createGPUTextData(
138
  props: GPUTextDataProps,
139
  options: {
140
    resources: GPUTextResources;
141
    sourceBatchIndex?: number;
142
    rowIndexBase?: number;
143
    glyphIndexBase?: number;
144
    rowCount: number;
145
    destroySource?: () => void;
146
  }
147
): GPUTextData {
148
  return new GPUTextDataImpl(props, {
15✔
149
    sourceBatchIndex: 0,
150
    rowIndexBase: 0,
151
    glyphIndexBase: 0,
152
    ...options
153
  });
154
}
155

156
/** @internal */
157
export function getGPUTextDataProps(data: GPUTextData): GPUTextDataProps {
158
  return (data as GPUTextDataImpl).getInternalProps();
13✔
159
}
160

161
function makeGPUTextStats(props: GPUTextDataProps, rowCount: number): GPUTextStats {
162
  if (props.strategy === 'attribute') {
15!
163
    const state = props.state;
15✔
164
    return {
15✔
165
      strategy: props.strategy,
166
      rowCount,
167
      glyphCount: state.glyphLayout.glyphCount,
168
      sourceBatchCount: 1,
169
      renderBatchCount: state.renderBatches.length,
170
      preparationTimeMs: state.glyphAttributeBuildTimeMs,
171
      retainedByteLength: state.glyphAttributeByteLength,
172
      transientByteLength: 0
173
    };
174
  }
NEW
175
  const state = props.state;
×
NEW
176
  return {
×
177
    strategy: props.strategy,
178
    rowCount,
179
    glyphCount: state.glyphCount,
180
    sourceBatchCount: 1,
181
    renderBatchCount: state.renderBatches.length,
182
    preparationTimeMs: state.glyphAttributeBuildTimeMs + state.compactStreamBuildTimeMs,
183
    retainedByteLength:
184
      state.glyphAttributeByteLength +
185
      state.compactStreamByteLength +
186
      state.rowStorageByteLength +
187
      state.glyphDefinitionStorageByteLength,
188
    transientByteLength: state.transientComputeInputByteLength
189
  };
190
}
191

192
function destroyGPUTextState(props: GPUTextDataProps): void {
193
  if (props.strategy === 'attribute') {
15!
194
    props.state.destroy();
15✔
195
    return;
15✔
196
  }
NEW
197
  props.state.destroy();
×
198
}
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