Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow access to SourceCache in custom layers #5477

Open
dsshep opened this issue Feb 9, 2025 · 1 comment
Open

Allow access to SourceCache in custom layers #5477

dsshep opened this issue Feb 9, 2025 · 1 comment

Comments

@dsshep
Copy link
Contributor

dsshep commented Feb 9, 2025

User Story

As a developer I can access the SourceCache in a Custom Layer, so that I don't have to reimplement the functionality for Custom Layers.

Rationale

As far as I am aware, Custom Layers have no access to SourceCache. Thus, when implementing a Custom Layer, the machinery around fetching and preparing tiles cannot be used and must be (re)implemented.

If a source property is provided on the custom layer, the relevant SourceCache should already be retrieved for the layer in painter.ts:

renderLayer(painter: Painter, sourceCache: SourceCache, layer: StyleLayer, coords: Array<OverscaledTileID>, renderOptions: RenderOptions) {
if (layer.isHidden(this.transform.zoom)) return;
if (layer.type !== 'background' && layer.type !== 'custom' && !(coords || []).length) return;
this.id = layer.id;
if (isSymbolStyleLayer(layer)) {
drawSymbols(painter, sourceCache, layer, coords, this.style.placement.variableOffsets, renderOptions);
} else if (isCircleStyleLayer(layer)) {
drawCircles(painter, sourceCache, layer, coords, renderOptions);
} else if (isHeatmapStyleLayer(layer)) {
drawHeatmap(painter, sourceCache, layer, coords, renderOptions);
} else if (isLineStyleLayer(layer)) {
drawLine(painter, sourceCache, layer, coords, renderOptions);
} else if (isFillStyleLayer(layer)) {
drawFill(painter, sourceCache, layer, coords, renderOptions);
} else if (isFillExtrusionStyleLayer(layer)) {
drawFillExtrusion(painter, sourceCache, layer, coords, renderOptions);
} else if (isHillshadeStyleLayer(layer)) {
drawHillshade(painter, sourceCache, layer, coords, renderOptions);
} else if (isRasterStyleLayer(layer)) {
drawRaster(painter, sourceCache, layer, coords, renderOptions);
} else if (isBackgroundStyleLayer(layer)) {
drawBackground(painter, sourceCache, layer, coords, renderOptions);
} else if (isCustomStyleLayer(layer)) {
drawCustom(painter, sourceCache, layer, renderOptions);
}
}

Where it is going missing is in the CustomRenderMethodInput type in draw_custom.ts:

export function drawCustom(painter: Painter, sourceCache: SourceCache, layer: CustomStyleLayer, renderOptions: RenderOptions) {
const {isRenderingGlobe} = renderOptions;
const context = painter.context;
const implementation = layer.implementation;
const projection = painter.style.projection;
const transform = painter.transform;
const projectionData = transform.getProjectionDataForCustomLayer(isRenderingGlobe);
const customLayerArgs: CustomRenderMethodInput = {
farZ: transform.farZ,
nearZ: transform.nearZ,
fov: transform.fov * Math.PI / 180, // fov converted to radians
modelViewProjectionMatrix: transform.modelViewProjectionMatrix,
projectionMatrix: transform.projectionMatrix,
shaderData: {
variantName: projection.shaderVariantName,
vertexShaderPrelude: `const float PI = 3.141592653589793;\nuniform mat4 u_projection_matrix;\n${projection.shaderPreludeCode.vertexSource}`,
define: projection.shaderDefine,
},
defaultProjectionData: projectionData,
};
const renderingMode = implementation.renderingMode ? implementation.renderingMode : '2d';
if (painter.renderPass === 'offscreen') {
const prerender = implementation.prerender;
if (prerender) {
painter.setCustomLayerDefaults();
context.setColorMode(painter.colorModeForRenderPass());
prerender.call(implementation, context.gl, customLayerArgs);
context.setDirty();
painter.setBaseState();
}
} else if (painter.renderPass === 'translucent') {
painter.setCustomLayerDefaults();
context.setColorMode(painter.colorModeForRenderPass());
context.setStencilMode(StencilMode.disabled);
const depthMode = renderingMode === '3d' ?
painter.getDepthModeFor3D() :
painter.getDepthModeForSublayer(0, DepthMode.ReadOnly);
context.setDepthMode(depthMode);
implementation.render(context.gl, customLayerArgs);
context.setDirty();
painter.setBaseState();
context.bindFramebuffer.set(null);
}
}

If it was added to this type, prerender and render would receive it as part of the args parameter. At the same time, it's worth passing Array<OverscaledTileID> from painter as well.

Impact

Any custom layers have to re-implement fetching, sorting, triangulating (if relevant) etc. the source data.

Happy to submit a PR on this if there isn't a better work around!

@HarelM
Copy link
Collaborator

HarelM commented Feb 9, 2025

The problem with exposing source cache to custom layer is the API surface and the need to maintain it.
You can see other PR around adding more fields to custom layer and the same problem around it.
I would advise to start with using internal fields and see if it's enough, otherwise, there will be a need to expose something a lot smaller...

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

No branches or pull requests

2 participants