-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
index-buffer.js
244 lines (214 loc) · 7.82 KB
/
index-buffer.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
import { Debug } from '../../core/debug.js';
import { TRACEID_VRAM_IB } from '../../core/constants.js';
import {
BUFFER_STATIC, INDEXFORMAT_UINT16, INDEXFORMAT_UINT32, typedArrayIndexFormatsByteSize
} from './constants.js';
let id = 0;
/**
* An index buffer stores index values into a {@link VertexBuffer}. Indexed graphical primitives
* can normally utilize less memory that unindexed primitives (if vertices are shared).
*
* Typically, index buffers are set on {@link Mesh} objects.
*
* @category Graphics
*/
class IndexBuffer {
/**
* Create a new IndexBuffer instance.
*
* @param {import('./graphics-device.js').GraphicsDevice} graphicsDevice - The graphics device
* used to manage this index buffer.
* @param {number} format - The type of each index to be stored in the index buffer. Can be:
*
* - {@link INDEXFORMAT_UINT8}
* - {@link INDEXFORMAT_UINT16}
* - {@link INDEXFORMAT_UINT32}
* @param {number} numIndices - The number of indices to be stored in the index buffer.
* @param {number} [usage] - The usage type of the vertex buffer. Can be:
*
* - {@link BUFFER_DYNAMIC}
* - {@link BUFFER_STATIC}
* - {@link BUFFER_STREAM}
*
* Defaults to {@link BUFFER_STATIC}.
* @param {ArrayBuffer} [initialData] - Initial data. If left unspecified, the index buffer
* will be initialized to zeros.
* @param {object} [options] - Object for passing optional arguments.
* @param {boolean} [options.storage] - Defines if the index buffer can be used as a storage
* buffer by a compute shader. Defaults to false. Only supported on WebGPU.
* @example
* // Create an index buffer holding 3 16-bit indices. The buffer is marked as
* // static, hinting that the buffer will never be modified.
* const indices = new UInt16Array([0, 1, 2]);
* const indexBuffer = new pc.IndexBuffer(graphicsDevice,
* pc.INDEXFORMAT_UINT16,
* 3,
* pc.BUFFER_STATIC,
* indices);
*/
constructor(graphicsDevice, format, numIndices, usage = BUFFER_STATIC, initialData, options) {
// By default, index buffers are static (better for performance since buffer data can be cached in VRAM)
this.device = graphicsDevice;
this.format = format;
this.numIndices = numIndices;
this.usage = usage;
this.id = id++;
this.impl = graphicsDevice.createIndexBufferImpl(this, options);
// Allocate the storage
const bytesPerIndex = typedArrayIndexFormatsByteSize[format];
this.bytesPerIndex = bytesPerIndex;
this.numBytes = this.numIndices * bytesPerIndex;
if (initialData) {
this.setData(initialData);
} else {
this.storage = new ArrayBuffer(this.numBytes);
}
this.adjustVramSizeTracking(graphicsDevice._vram, this.numBytes);
this.device.buffers.push(this);
}
/**
* Frees resources associated with this index buffer.
*/
destroy() {
// stop tracking the index buffer
const device = this.device;
const idx = device.buffers.indexOf(this);
if (idx !== -1) {
device.buffers.splice(idx, 1);
}
if (this.device.indexBuffer === this) {
this.device.indexBuffer = null;
}
if (this.impl.initialized) {
this.impl.destroy(device);
this.adjustVramSizeTracking(device._vram, -this.storage.byteLength);
}
}
adjustVramSizeTracking(vram, size) {
Debug.trace(TRACEID_VRAM_IB, `${this.id} size: ${size} vram.ib: ${vram.ib} => ${vram.ib + size}`);
vram.ib += size;
}
/**
* Called when the rendering context was lost. It releases all context related resources.
*
* @ignore
*/
loseContext() {
this.impl.loseContext();
}
/**
* Returns the data format of the specified index buffer.
*
* @returns {number} The data format of the specified index buffer. Can be:
*
* - {@link INDEXFORMAT_UINT8}
* - {@link INDEXFORMAT_UINT16}
* - {@link INDEXFORMAT_UINT32}
*/
getFormat() {
return this.format;
}
/**
* Returns the number of indices stored in the specified index buffer.
*
* @returns {number} The number of indices stored in the specified index buffer.
*/
getNumIndices() {
return this.numIndices;
}
/**
* Gives access to the block of memory that stores the buffer's indices.
*
* @returns {ArrayBuffer} A contiguous block of memory where index data can be written to.
*/
lock() {
return this.storage;
}
/**
* Signals that the block of memory returned by a call to the lock function is ready to be
* given to the graphics hardware. Only unlocked index buffers can be set on the currently
* active device.
*/
unlock() {
// Upload the new index data
this.impl.unlock(this);
}
/**
* Set preallocated data on the index buffer.
*
* @param {ArrayBuffer} data - The index data to set.
* @returns {boolean} True if the data was set successfully, false otherwise.
* @ignore
*/
setData(data) {
if (data.byteLength !== this.numBytes) {
Debug.error(`IndexBuffer: wrong initial data size: expected ${this.numBytes}, got ${data.byteLength}`);
return false;
}
this.storage = data;
this.unlock();
return true;
}
/**
* Get the appropriate typed array from an index buffer.
*
* @returns {Uint8Array|Uint16Array|Uint32Array} The typed array containing the index data.
* @private
*/
_lockTypedArray() {
const lock = this.lock();
const indices = this.format === INDEXFORMAT_UINT32 ? new Uint32Array(lock) :
(this.format === INDEXFORMAT_UINT16 ? new Uint16Array(lock) : new Uint8Array(lock));
return indices;
}
/**
* Copies the specified number of elements from data into index buffer. Optimized for
* performance from both typed array as well as array.
*
* @param {Uint8Array|Uint16Array|Uint32Array|number[]} data - The data to write.
* @param {number} count - The number of indices to write.
* @ignore
*/
writeData(data, count) {
const indices = this._lockTypedArray();
// if data contains more indices than needed, copy from its subarray
if (data.length > count) {
// if data is typed array
if (ArrayBuffer.isView(data)) {
data = data.subarray(0, count);
indices.set(data);
} else {
// data is array, copy right amount manually
for (let i = 0; i < count; i++)
indices[i] = data[i];
}
} else {
// copy whole data
indices.set(data);
}
this.unlock();
}
/**
* Copies index data from index buffer into provided data array.
*
* @param {Uint8Array|Uint16Array|Uint32Array|number[]} data - The data array to write to.
* @returns {number} The number of indices read.
* @ignore
*/
readData(data) {
// note: there is no need to unlock this buffer, as we are only reading from it
const indices = this._lockTypedArray();
const count = this.numIndices;
if (ArrayBuffer.isView(data)) {
// destination data is typed array
data.set(indices);
} else {
// data is array, copy right amount manually
data.length = 0;
for (let i = 0; i < count; i++)
data[i] = indices[i];
}
return count;
}
}
export { IndexBuffer };