Skip to content

Commit eef33f1

Browse files
committed
refactor buffer storage 4
1 parent c1c0448 commit eef33f1

File tree

3 files changed

+78
-36
lines changed

3 files changed

+78
-36
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "deepscatter",
33
"type": "module",
4-
"version": "3.0.0-next.43",
4+
"version": "3.0.0-next.45",
55
"description": "Fast, animated zoomable scatterplots scaling to billions of points",
66
"files": [
77
"dist"

src/regl_rendering.ts

Lines changed: 66 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,19 +1000,24 @@ export class BufferManager {
10001000
// but since they relate to Regl,
10011001
// I want them in this file instead.
10021002

1003+
1004+
10031005
private regl: Regl;
10041006
public renderer: ReglRenderer;
1005-
private bufferMap: WeakMap<ArrayBufferView, DS.BufferLocation> = new Map();
1007+
private bufferMap: WeakMap<ArrayBufferView, DS.BufferLocation<Buffer>> = new Map();
10061008
private arrayMap: TupleMap<string | Tile, ArrayBufferView> = new TupleMap();
1007-
public ixInTileBuffer: DS.BufferLocation;
1009+
public ixInTileBuffer: DS.BufferLocation<Buffer>;
10081010
// A list of integers. Used internally.
10091011
private _integer_array?: Float32Array;
10101012
// A buffer populated from that list.
10111013
private _integer_buffer?: Buffer;
10121014

10131015
constructor(renderer: ReglRenderer) {
1014-
this.regl = renderer.regl;
10151016
this.renderer = renderer;
1017+
this.regl = renderer.regl;
1018+
1019+
console.log(this.regl)
1020+
10161021
// Reuse the same buffer for all `ix_in_tile` keys, because
10171022
// it's just a set of integers going up.
10181023
this.ixInTileBuffer = {
@@ -1041,7 +1046,7 @@ export class BufferManager {
10411046
return this._integer_buffer;
10421047
}
10431048

1044-
get(k: Some<string | Tile>): DS.BufferLocation | null {
1049+
get(k: Some<string | Tile>): DS.BufferLocation<Buffer> | null {
10451050
const a = this.bufferMap.get(this.arrayMap.get(k));
10461051
return a;
10471052
}
@@ -1249,7 +1254,7 @@ export function getNestedVector(
12491254
return column;
12501255
}
12511256

1252-
class MultipurposeBufferSet {
1257+
export abstract class BufferSet<BufferType = Buffer, BufferLocationType extends DS.BufferLocation<BufferType> = DS.BufferLocation<BufferType>> {
12531258
// An abstraction creating an expandable set of buffers that can be subdivided
12541259
// to put more than one variable on the same
12551260
// block of memory. Reusing buffers this way can have performance benefits over allocating
@@ -1258,53 +1263,51 @@ class MultipurposeBufferSet {
12581263
// The general purpose here is to call 'allocate_block' that releases a block of memory
12591264
// to use in creating a new array to be passed to regl.
12601265

1261-
private regl: Regl;
1262-
private buffers: Buffer[];
1266+
protected buffers: BufferType[];
12631267
public buffer_size: number;
1264-
private pointer: number; // the byte offset to start the next allocation from.
1265-
private freed_buffers: DS.BufferLocation[] = [];
1268+
protected pointer: number; // the byte offset to start the next allocation from.
1269+
protected freed_buffers: BufferLocationType[] = [];
12661270
/**
12671271
*
12681272
* @param regl the Regl context we're using.
12691273
* @param buffer_size The number of bytes on each strip of memory that we'll ask for.
12701274
*/
12711275

1272-
constructor(regl: Regl, buffer_size: number) {
1273-
this.regl = regl;
1276+
constructor(buffer_size: number) {
12741277
this.buffer_size = buffer_size;
12751278
this.buffers = [];
12761279
// Track the ends in case we want to allocate smaller items.
12771280
this.pointer = 0;
1278-
this.generate_new_buffer();
12791281
}
12801282

12811283
generate_new_buffer() {
12821284
if (this.buffers.length && this.buffer_size - this.pointer > 128) {
12831285
// mark any remaining space longer than 128 bytes as available.
1284-
this.freed_buffers.push({
1285-
buffer: this.buffers[0],
1286-
offset: this.pointer,
1287-
stride: 4, // meaningless here.
1288-
byte_size: this.buffer_size - this.pointer,
1289-
});
1286+
console.log("YOOO")
1287+
const leftover = this._create_leftover_buffer();
1288+
this.freed_buffers.push(leftover);
12901289
}
12911290
this.pointer = 0;
12921291
// Adds to beginning of list.
12931292
this.buffers.unshift(
1294-
this.regl.buffer({
1295-
type: 'float',
1296-
length: this.buffer_size,
1297-
usage: 'dynamic',
1298-
}),
1293+
this._create_buffer()
12991294
);
13001295
}
1296+
1297+
// We need a method to create a new instance of the buffer type.
1298+
abstract _create_buffer() : BufferType;
1299+
1300+
// And one to mark the leftover space on the current buffer as available
1301+
// so it can be re-allocated later if needed.
1302+
abstract _create_leftover_buffer() : BufferLocationType;
1303+
13011304
/**
13021305
* Freeing a block means just adding its space back into the list of open blocks.
13031306
* There's no need to actually zero out the memory or anything.
13041307
*
13051308
* @param buff The location of the buffer we're done with.
13061309
*/
1307-
free_block(buff: DS.BufferLocation) {
1310+
free_block(buff: BufferLocationType) {
13081311
this.freed_buffers.push(buff);
13091312
}
13101313

@@ -1315,9 +1318,11 @@ class MultipurposeBufferSet {
13151318
* @returns
13161319
*/
13171320

1318-
allocate_block(items: number, bytes_per_item: number): DS.BufferLocation {
1321+
allocate_block(items: number, bytes_per_item: number = 1): DS.BufferLocation<BufferType> {
13191322
// Call dibs on a block of this buffer.
13201323
// NB size is in **bytes**
1324+
1325+
13211326
const bytes_needed = items * bytes_per_item;
13221327
let i = 0;
13231328
for (const buffer_loc of this.freed_buffers) {
@@ -1331,32 +1336,64 @@ class MultipurposeBufferSet {
13311336
buffer: buffer_loc.buffer,
13321337
offset: buffer_loc.offset,
13331338
stride: bytes_per_item,
1334-
byte_size: bytes_needed,
1339+
size: bytes_needed,
13351340
};
13361341
return v;
13371342
}
13381343
i += 1;
13391344
}
13401345

1341-
if (this.pointer + items * bytes_per_item > this.buffer_size) {
1346+
// If we have no buffers, or the last one is full, move to the next one.
1347+
if (this.buffers.length === 0 || this.pointer + items * bytes_per_item > this.buffer_size) {
13421348
// May lead to ragged ends. Could be smarter about reallocation here,
13431349
// too.
1350+
console.log("GENERATING")
13441351
this.generate_new_buffer();
13451352
}
13461353

1347-
const value: DS.BufferLocation = {
1354+
const value: DS.BufferLocation<BufferType> = {
13481355
// First slot stores the active buffer.
13491356
buffer: this.buffers[0],
13501357
offset: this.pointer,
13511358
stride: bytes_per_item,
13521359
byte_size: items * bytes_per_item,
13531360
};
1354-
1361+
console.log(value.byte_size)
13551362
this.pointer += items * bytes_per_item;
13561363
return value;
13571364
}
13581365
}
13591366

1367+
class MultipurposeBufferSet extends BufferSet<Buffer> {
1368+
1369+
private regl: Regl;
1370+
constructor(regl: Regl, buffer_size: number) {
1371+
console.log("USING REGL", regl)
1372+
super(buffer_size);
1373+
this.regl = regl;
1374+
}
1375+
1376+
_create_buffer() {
1377+
console.log("A")
1378+
const buffer = this.regl.buffer({
1379+
type: 'float',
1380+
length: this.buffer_size,
1381+
usage: 'dynamic',
1382+
});
1383+
console.log("C")
1384+
return buffer
1385+
}
1386+
1387+
_create_leftover_buffer() : DS.BufferLocation<Buffer> {
1388+
return {
1389+
buffer: this.buffers[0],
1390+
offset: this.pointer,
1391+
stride: 4, // meaningless here.
1392+
byte_size: this.buffer_size - this.pointer,
1393+
}
1394+
}
1395+
}
1396+
13601397
/**
13611398
*
13621399
* @param prefs The preferences object to be used.

src/types.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ import type {
1111
Timestamp,
1212
Utf8,
1313
Vector,
14+
Type,
1415
} from 'apache-arrow';
1516
import type { Renderer } from './rendering';
1617
import type { Deeptable } from './Deeptable';
1718
import type { ConcreteAesthetic } from './aesthetics/StatefulAesthetic';
18-
import type { Buffer } from 'regl';
1919
import type { DataSelection } from './selection';
2020
import { Scatterplot } from './scatterplot';
2121
import { ZoomTransform } from 'd3-zoom';
@@ -29,15 +29,20 @@ export type { Renderer, Deeptable, ConcreteAesthetic };
2929
* can find data on it.
3030
*
3131
* Note that the byte_size is *for the buffer*, and that individual elements
32-
* may take views of it less than the byte_size.
32+
* may take views of it less` than the byte_size.
3333
*/
34-
export type BufferLocation = {
35-
buffer: Buffer;
34+
export interface BufferLocation<T> {
35+
buffer: T;
3636
offset: number;
37-
stride: number;
38-
byte_size: number; // in bytes;
37+
stride?: number;
38+
byte_size?: number; // in bytes;
3939
};
4040

41+
export type WebGPUBufferLocation = BufferLocation<GPUBuffer> & {
42+
arrowType?: Type,
43+
paddedSize: number;
44+
}
45+
4146
export type Newable<T> = { new (...args: unknown[]): T };
4247
export type PointFunction<T = number> = (p: StructRowProxy) => T;
4348

0 commit comments

Comments
 (0)