Skip to content

Commit

Permalink
Aggregation UBO 2/2 (#9133)
Browse files Browse the repository at this point in the history
  • Loading branch information
felixpalmer committed Sep 3, 2024
1 parent 9a44132 commit afe6c32
Show file tree
Hide file tree
Showing 14 changed files with 256 additions and 119 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {NumberArray3, NumberArray4} from '@math.gl/core';
import {ShaderModule} from '@luma.gl/shadertools';
import {Texture} from '@luma.gl/core';

const uniformBlock = /* glsl */ `\
uniform aggregatorTransformUniforms {
ivec4 binIdRange;
bvec3 isCount;
bvec3 isMean;
float naN;
} aggregatorTransform;
`;

export type AggregatorTransformProps = {
binIdRange: NumberArray4;
isCount: NumberArray3;
isMean: NumberArray3;
naN: number;
bins: Texture;
};

export const aggregatorTransformUniforms = {
name: 'aggregatorTransform',
vs: uniformBlock,
uniformTypes: {
binIdRange: 'vec4<i32>',
isCount: 'vec3<f32>',
isMean: 'vec3<f32>',
naN: 'f32'
}
} as const satisfies ShaderModule<AggregatorTransformProps>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {NumberArray2, NumberArray4} from '@math.gl/core';
import {ShaderModule} from '@luma.gl/shadertools';

const uniformBlock = /* glsl */ `\
uniform binSorterUniforms {
ivec4 binIdRange;
ivec2 targetSize;
} binSorter;
`;

export type BinSorterProps = {
binIdRange: NumberArray4;
targetSize: NumberArray2;
};

export const binSorterUniforms = {
name: 'binSorter',
vs: uniformBlock,
uniformTypes: {
binIdRange: 'vec4<i32>',
targetSize: 'vec2<i32>'
}
} as const satisfies ShaderModule<BinSorterProps>;
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import type {WebGLAggregatorProps} from './webgl-aggregator';
import type {AggregationOperation} from '../aggregator';

import {TEXTURE_WIDTH} from './webgl-bin-sorter';
import {
AggregatorTransformProps,
aggregatorTransformUniforms
} from './aggregation-transform-uniforms';
import {NumberArray3} from '@math.gl/core';

const MAX_FLOAT32 = 3e38;

Expand All @@ -30,6 +35,9 @@ export class WebGLAggregationTransform {
this.device = device;
this.channelCount = props.channelCount;
this.transform = createTransform(device, props);
// Passed in as uniform because 1) there is no GLSL symbol for NaN 2) any expression that exploits undefined behavior to produces NaN
// will subject to platform differences and shader optimization
this.transform.model.shaderInputs.setProps({aggregatorTransform: {naN: NaN}});
this.domainFBO = createRenderTarget(device, 2, 1);
}

Expand Down Expand Up @@ -58,14 +66,15 @@ export class WebGLAggregationTransform {
setDimensions(binCount: number, binIdRange: [number, number][]) {
const {model, transformFeedback} = this.transform;
model.setVertexCount(binCount);
model.setUniforms({
const aggregatorTransformProps: Partial<AggregatorTransformProps> = {
binIdRange: [
binIdRange[0][0],
binIdRange[0][1],
binIdRange[1]?.[0] || 0,
binIdRange[1]?.[1] || 0
]
});
};
model.shaderInputs.setProps({aggregatorTransform: aggregatorTransformProps});

// Only destroy existing buffer if it is not large enough
const binBufferByteLength = binCount * binIdRange.length * 4;
Expand All @@ -90,11 +99,14 @@ export class WebGLAggregationTransform {
const transform = this.transform;
const target = this.domainFBO;

transform.model.setUniforms({
isCount: Array.from({length: 3}, (_, i) => (operations[i] === 'COUNT' ? 1 : 0)),
isMean: Array.from({length: 3}, (_, i) => (operations[i] === 'MEAN' ? 1 : 0))
});
transform.model.setBindings({bins});
const isCount = [0, 1, 2].map(i => (operations[i] === 'COUNT' ? 1 : 0));
const isMean = [0, 1, 2].map(i => (operations[i] === 'MEAN' ? 1 : 0));
const aggregatorTransformProps: Partial<AggregatorTransformProps> = {
isCount: isCount as NumberArray3,
isMean: isMean as NumberArray3,
bins
};
transform.model.shaderInputs.setProps({aggregatorTransform: aggregatorTransformProps});

transform.run({
id: 'gpu-aggregation-domain',
Expand All @@ -117,10 +129,6 @@ function createTransform(device: Device, props: WebGLAggregatorProps): BufferTra
#version 300 es
#define SHADER_NAME gpu-aggregation-domain-vertex
uniform ivec4 binIdRange;
uniform bvec3 isCount;
uniform bvec3 isMean;
uniform float naN;
uniform sampler2D bins;
#if NUM_DIMS == 1
Expand All @@ -142,21 +150,21 @@ void main() {
int col = gl_VertexID - row * SAMPLER_WIDTH;
vec4 weights = texelFetch(bins, ivec2(col, row), 0);
vec3 value3 = mix(
mix(weights.rgb, vec3(weights.a), isCount),
mix(weights.rgb, vec3(weights.a), aggregatorTransform.isCount),
weights.rgb / max(weights.a, 1.0),
isMean
aggregatorTransform.isMean
);
if (weights.a == 0.0) {
value3 = vec3(naN);
value3 = vec3(aggregatorTransform.naN);
}
#if NUM_DIMS == 1
binIds = float(gl_VertexID + binIdRange.x);
binIds = float(gl_VertexID + aggregatorTransform.binIdRange.x);
#else
int y = gl_VertexID / (binIdRange.y - binIdRange.x);
int x = gl_VertexID - y * (binIdRange.y - binIdRange.x);
binIds.y = float(y + binIdRange.z);
binIds.x = float(x + binIdRange.x);
int y = gl_VertexID / (aggregatorTransform.binIdRange.y - aggregatorTransform.binIdRange.x);
int x = gl_VertexID - y * (aggregatorTransform.binIdRange.y - aggregatorTransform.binIdRange.x);
binIds.y = float(y + aggregatorTransform.binIdRange.z);
binIds.x = float(x + aggregatorTransform.binIdRange.x);
#endif
#if NUM_CHANNELS == 3
Expand Down Expand Up @@ -219,6 +227,7 @@ void main() {
vs,
fs,
topology: 'point-list',
modules: [aggregatorTransformUniforms],
parameters: {
blend: true,
blendColorSrcFactor: 'one',
Expand All @@ -233,11 +242,6 @@ void main() {
NUM_CHANNELS: props.channelCount,
SAMPLER_WIDTH: TEXTURE_WIDTH
},
uniforms: {
// Passed in as uniform because 1) there is no GLSL symbol for NaN 2) any expression that exploits undefined behavior to produces NaN
// will subject to platform differences and shader optimization
naN: NaN
},
varyings: ['binIds', 'values'],
disableWarnings: true
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ export class WebGLAggregator implements Aggregator {
if (!deepEqual(props.binOptions, oldProps.binOptions, 2)) {
this.setNeedsUpdate();
}
this.binSorter.setModelProps({uniforms: props.binOptions});
this.binSorter.model.shaderInputs.setProps({binOptions: props.binOptions});
}
if (props.attributes) {
const attributeBuffers: Record<string, Buffer> = {};
Expand Down Expand Up @@ -252,7 +252,7 @@ export class WebGLAggregator implements Aggregator {
}

if (opts.moduleSettings) {
this.binSorter.setModelProps(opts);
this.binSorter.setModelProps({moduleSettings: opts.moduleSettings});
}

const {operations} = this.props;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {createRenderTarget} from './utils';
import type {Device, Framebuffer, Texture} from '@luma.gl/core';
import type {WebGLAggregatorProps} from './webgl-aggregator';
import type {AggregationOperation} from '../aggregator';
import {BinSorterProps, binSorterUniforms} from './bin-sorter-uniforms';

const COLOR_CHANNELS = [0x1, 0x2, 0x4, 0x8]; // GPU color mask RED, GREEN, BLUE, ALPHA
const MAX_FLOAT32 = 3e38;
Expand Down Expand Up @@ -71,15 +72,16 @@ export class WebGLBinSorter {
this.binsFBO.resize({width, height});
}

this.model.setUniforms({
const binSorterProps: BinSorterProps = {
binIdRange: [
binIdRange[0][0],
binIdRange[0][1],
binIdRange[1]?.[0] || 0,
binIdRange[1]?.[1] || 0
],
targetSize: [this.binsFBO.width, this.binsFBO.height]
});
};
this.model.shaderInputs.setProps({binSorter: binSorterProps});
}

setModelProps(
Expand All @@ -89,9 +91,6 @@ export class WebGLBinSorter {
>
) {
const model = this.model;
if (props.uniforms) {
model.setUniforms(props.uniforms);
}
if (props.attributes) {
model.setAttributes(props.attributes);
}
Expand All @@ -102,9 +101,17 @@ export class WebGLBinSorter {
model.setVertexCount(props.vertexCount);
}
if (props.moduleSettings) {
// TODO v9.1 - remove after migrate to UBO
model.updateModuleSettings(props.moduleSettings);
model.shaderInputs.setProps({project: props.moduleSettings});
const {viewport, devicePixelRatio, modelMatrix, coordinateSystem, coordinateOrigin} =
props.moduleSettings;
model.shaderInputs.setProps({
project: {
viewport,
devicePixelRatio,
modelMatrix,
coordinateSystem,
coordinateOrigin
}
});
}
}

Expand Down Expand Up @@ -185,10 +192,10 @@ function createModel(device: Device, props: WebGLAggregatorProps): Model {
void getBin(out int binId) {
ivec2 binId2;
getBin(binId2);
if (binId2.x < binIdRange.x || binId2.x >= binIdRange.y) {
if (binId2.x < binSorter.binIdRange.x || binId2.x >= binSorter.binIdRange.y) {
binId = -1;
} else {
binId = (binId2.y - binIdRange.z) * (binIdRange.y - binIdRange.x) + binId2.x;
binId = (binId2.y - binSorter.binIdRange.z) * (binSorter.binIdRange.y - binSorter.binIdRange.x) + binId2.x;
}
}
`;
Expand All @@ -198,24 +205,21 @@ void getBin(out int binId) {
#version 300 es
#define SHADER_NAME gpu-aggregation-sort-bins-vertex
uniform ivec4 binIdRange;
uniform ivec2 targetSize;
${userVs}
out vec3 v_Value;
void main() {
int binIndex;
getBin(binIndex);
binIndex = binIndex - binIdRange.x;
binIndex = binIndex - binSorter.binIdRange.x;
if (binIndex < 0) {
gl_Position = vec4(0.);
return;
}
int row = binIndex / targetSize.x;
int col = binIndex - row * targetSize.x;
vec2 position = (vec2(col, row) + 0.5) / vec2(targetSize) * 2.0 - 1.0;
int row = binIndex / binSorter.targetSize.x;
int col = binIndex - row * binSorter.targetSize.x;
vec2 position = (vec2(col, row) + 0.5) / vec2(binSorter.targetSize) * 2.0 - 1.0;
gl_Position = vec4(position, 0.0, 1.0);
gl_PointSize = 1.0;
Expand Down Expand Up @@ -250,7 +254,7 @@ void main() {
`;
const model = new Model(device, {
bufferLayout: props.bufferLayout,
modules: props.modules,
modules: [...(props.modules || []), binSorterUniforms],
defines: {...props.defines, NON_INSTANCED_MODEL: 1, NUM_CHANNELS: props.channelCount},
isInstanced: false,
vs,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type {ShaderModule} from '@luma.gl/shadertools';

const uniformBlock = /* glsl */ `\
uniform binOptionsUniforms {
vec2 cellOriginCommon;
vec2 cellSizeCommon;
} binOptions;
`;

export type BinOptions = {
cellOriginCommon: [number, number];
cellSizeCommon: [number, number];
};

export const binOptionsUniforms = {
name: 'binOptions',
vs: uniformBlock,
uniformTypes: {
cellOriginCommon: 'vec2<f32>',
cellSizeCommon: 'vec2<f32>'
}
} as const satisfies ShaderModule<BinOptions>;
Loading

0 comments on commit afe6c32

Please sign in to comment.