Skip to content

feat(segmentation_user_layer): add user shader for segmentation layers with support for segment properties - #1074

Open
chrisj wants to merge 16 commits into
google:masterfrom
AllenInstitute:cj-segment-color-user-shader
Open

feat(segmentation_user_layer): add user shader for segmentation layers with support for segment properties#1074
chrisj wants to merge 16 commits into
google:masterfrom
AllenInstitute:cj-segment-color-user-shader

Conversation

@chrisj

@chrisj chrisj commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

continuation of #862

@chrisj
chrisj force-pushed the cj-segment-color-user-shader branch 8 times, most recently from 07f7c7c to 7adf3fc Compare July 15, 2026 16:43
@chrisj
chrisj marked this pull request as ready for review July 15, 2026 16:43
@chrisj
chrisj force-pushed the cj-segment-color-user-shader branch from 7adf3fc to 53cfe9b Compare July 15, 2026 16:45

@seankmartin seankmartin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks nice, thanks for all the changes! In general the API in the shader seems pretty reasonable to me. I've not gotten to go through it all, but some small comments from what I have looked through. There are also some TODO markers and the likes, not sure if those are still relevant or you settled on the approach in those cases

colorGroupState.segmentColorHash.compute(color, objectId);
return color;
const { getShaderSegmentColor } = displayState;
return getShaderSegmentColor(objectId) ?? color;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we detect if the shader is the default one, and in that case use the old non-shader color path to display the colors in the UI for performance. I noticed that the segmentation menu can sometimes feel a bit more sluggish to go through, which seems pretty fair when you've chosen to use the segment shader and to me it seems fine. But if possible to avoid this slight hit if you didn't change your shader I think that would be good

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that is what I should do for now but maybe I should give a quick try at adding batching. I don't notice sluggishness but I do notice that the color doesn't load immediately if scrolling very fast on my machine. I can't replicate that on the main branch.

It's easy to add support to calculate many segment colors in a single draw call, the issue is that the segment list is designed so that each row is processed independently. But if I can get it working, it should be far more performant.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes a lot of sense, thanks Chris

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@seankmartin can you check if this deployment has noticeably better performance for you?

demo

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wow, that's so much better yes thanks @chrisj

const hasStringProperty = inlineProperties.properties.some(
(p) => p.type === "string",
);
if (!hasStringProperty) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is leftover but it does raise what we should do here. Shader error comes to mind, but then in theory the underlying data could change and lose a property. Maybe that's fine though.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah that was for demonstration as string properties are not common. But do you mean if a shader references a property that was later removed from the segment properties file? If so I think the current error "property does not exist" is correct.

});
}

function makeSkeletonShaderCodeWidget(layer: SegmentationUserLayer) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

Minor but the style of the element layout seems different on this new shader controls in the UI compared to the skeleton ones

Comment thread src/layer/segmentation/index.ts Outdated
}

export const DEFAULT_FRAGMENT_SEGMENT_COLOR = `
vec3 segmentColor(vec3 color, bool hasProperties, bool isStated) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh also minor but leading newline in the resulting shader here that probably is better left out

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also I should rename it from FRAGMENT becomes it is sometimes used in the vertex shader

@chrisj

chrisj commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

@seankmartin thanks for the review! I have some changes I'll push shortly that I noticed yesterday

@seankmartin

Copy link
Copy Markdown
Contributor

@seankmartin thanks for the review! I have some changes I'll push shortly that I noticed yesterday

sounds great, thanks!

@chrisj
chrisj force-pushed the cj-segment-color-user-shader branch 2 times, most recently from 00444f6 to 9f4e76c Compare July 20, 2026 15:28
@chrisj
chrisj force-pushed the cj-segment-color-user-shader branch 2 times, most recently from 72bcce9 to b3fd516 Compare August 13, 2026 16:56
@chrisj

chrisj commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

@seankmartin I simplified the performance optimizations and added it to this PR. I added a temporary setting that you can toggle with "q" to easily observe the difference. Can you give it a test to see if you are still see the big performance improvement? I can see the a difference when I press "q" on and off while dragging the scroll bar. If it looks good I'll revert those last few commits.

example

@seankmartin

Copy link
Copy Markdown
Contributor

@seankmartin I simplified the performance optimizations and added it to this PR. I added a temporary setting that you can toggle with "q" to easily observe the difference. Can you give it a test to see if you are still see the big performance improvement? I can see the a difference when I press "q" on and off while dragging the scroll bar. If it looks good I'll revert those last few commits.

example

Thanks @chrisj, that's great! And yes still much better for me when batched

@chrisj
chrisj force-pushed the cj-segment-color-user-shader branch from 7317500 to b3fd516 Compare August 17, 2026 13:34
chrisj added 6 commits August 18, 2026 16:42
…s + segment property ui control + segment properties in invlerp control
segment_list:
add prefetchBaseObjectColors - computes colors before rows are created
add updateMany - recomputes colors for all currently rendered rows following display-state changes

virtual_list:
add optional VirtualListSource.prefetch(start, end) callback. It is called before missing rows in that interval are constructed
@chrisj
chrisj force-pushed the cj-segment-color-user-shader branch 2 times, most recently from fc7512d to 775e56d Compare August 18, 2026 21:45
@chrisj
chrisj force-pushed the cj-segment-color-user-shader branch from 775e56d to c4c7d9d Compare August 19, 2026 14:55
toMerged: Uint32Array,
): InlineSegmentNumericalProperty {
const values = new Float32Array(numMerged);
const values = property.values.slice(0, numMerged);

@chrisj chrisj Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been diving into this change and need some thoughts.

This function is called when merging multiple segment property maps together. It was casting every numerical property values array to Float32Array. If the maps had differing sets of segments, each segment received a value of NaN for the numerical property of each map it was not in.

The easiest solution would be to just use a zero value and keep each values as it's original numerical type. Another option is to do that but add a validity mask. This is a rough idea of what that would look like: AllenInstitute@4e7a970

if (hasProp("myProperty")) {
  uint value = prop("myProperty");
  // use value
}

I'm leaning towards using 0 instead of NaN for non-float and skipping the validity mask as I imagine it won't have much use.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems reasonable to me to do the simpler version, I also can't imagine it's used too often

chrisj added 8 commits August 24, 2026 16:54
Previously, merged numerical properties were initialized with NaN, which
coerced integer typed arrays to zero while leaving float properties as NaN.
Allocate the merged values with the source typed-array constructor so missing
entries consistently default to zero, preserve the property datatype, and
expand the bounds to include zero.
@chrisj
chrisj force-pushed the cj-segment-color-user-shader branch from 7dac20e to 1784f69 Compare August 25, 2026 12:16
): InlineSegmentNumericalProperty {
const values = new Float32Array(numMerged);
values.fill(Number.NaN);
const values = new (property.values

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jbms are you good with this change?

759a4d6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants