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

Refactor usage of implicit parameter to an explicit one when rendering #5020

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

ibesora
Copy link
Collaborator

@ibesora ibesora commented Nov 8, 2024

This PR aims to refactor our codebase a little bit in order to move away of what, IMHO, are code smells.

First, some context.
The Painter object mostly contains properties that describe how things are going to be rendered via the underlying rendering API (i.e. vertex and index buffers, stencil buffer definitions, depth range, etc.) but it also contains the Style object which in itself describes how things should look like.
draw_* functions (i.e. draw_background) get both the Painter object and StyleLayer object, which is basically the subset of the Style that we need to render a given layer.

There are various places in the draw_* functions where we use painter.style to get information about the current rendering mode:

  • We use painter.style.map.terrain to know if we are rendering with terrain
  • We use painter.style.projection.name to know if we are rendering using globe or mercator projections

and change the drawing behaviour according to that. Since those properties are deep into the Painter object, you might get two similar-looking draw_* calls with very different results.

This PR replaces checks for terrain rendering via the painter.style property with an extra renderLayer parameter that tells a given draw_* function if it's being rendered to a texture.

A follow-up idea would be to remove style entirely from the Painter object and add all the properties that are needed for the various draw_* functions into the Painter object itself.

Cc @birkskyum since we talked about this.

Launch Checklist

  • Confirm your changes do not include backports from Mapbox projects (unless with compliant license) - if you are not sure about this, please ask!
  • Briefly describe the changes in this PR.
  • Link to related issues.
  • Include before/after visuals or gifs if this PR includes visual changes.
  • Write tests for all new functionality.
  • Document any changes to public APIs.
  • Post benchmark scores.
  • Add an entry to CHANGELOG.md under the ## main section.

@codecov-commenter
Copy link

codecov-commenter commented Nov 8, 2024

Codecov Report

Attention: Patch coverage is 98.58156% with 2 lines in your changes missing coverage. Please review.

Project coverage is 88.43%. Comparing base (8555091) to head (482a8cd).
Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
src/render/draw_line.ts 80.00% 0 Missing and 1 partial ⚠️
src/render/render_to_texture.ts 83.33% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5020      +/-   ##
==========================================
- Coverage   89.25%   88.43%   -0.82%     
==========================================
  Files         269      269              
  Lines       38286    38310      +24     
  Branches     2347     2478     +131     
==========================================
- Hits        34172    33880     -292     
- Misses       3117     3393     +276     
- Partials      997     1037      +40     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@birkskyum
Copy link
Member

birkskyum commented Nov 8, 2024

Thanks for cleaning up - I think this is a good path.

To make it even more explicit what happens, can we maybe flip the bools, so that they're apply (or enable) instead of ignore? My thinking is that it's easier to understand what happens if we turn on logic, and it opens for later on just passing in the transform we want to run, instead of focusing on disabling the ones that we don't want to run. There's effectively a lot of double-negation in the current design.

So effectively this:

this.getProjectionData({
  ignoreGlobeMatrix: true,
//ignoreTerrainMatrix: false  hidden default value
});

Becomes this:

this.getProjectionData({
//applyGlobeMatrix: false, hidden default value
  applyTerrainMatrix: true
});

So it says what it does, not what it doesn't.

@HarelM
Copy link
Collaborator

HarelM commented Nov 8, 2024

I think this is great!
I would also look in the code and find the places where "this" is being passed down. Solving those places will prevent this behavior I believe where you look deep into objects to find references to other objects.

Since we are in the middle of a breaking change version release, now would be a great time to move objects around and clean some historical bad decisions...

src/render/painter.ts Outdated Show resolved Hide resolved
@ibesora
Copy link
Collaborator Author

ibesora commented Nov 12, 2024

I've updated this PR with some of your suggestions:

  • To remove reading globe from the style as suggested here, instead of adding another boolean to all the draw_* functions, I moved those into a type called RenderOptions that will be able to grow with more flags.
  • I also added type predicate functions to change remove the layer as any casts.

I'll tackle removing style from the Painter object in another PR

@@ -62,6 +72,11 @@ type PainterOptions = {
fadeDuration: number;
};

export type RenderFlags = {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think "Options" is used in the code. I would consider renaming this to "RenderOptions".

switch (layer.type) {
case 'symbol':
drawSymbols(painter, sourceCache, layer as any, coords, this.style.placement.variableOffsets);
switch (true) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I find this odd TBH, maybe a if ...else if... Will be better here? It might be just that I'm not used to it... IDK.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, to be fair it was a little bit weird. Changed it to an if...else block and it feels better.

import type {SourceCache} from '../source/source_cache';
import type {BackgroundStyleLayer} from '../style/style_layer/background_style_layer';
import {OverscaledTileID} from '../source/tile_id';
import {coveringTiles} from '../geo/projection/covering_tiles';

export function drawBackground(painter: Painter, sourceCache: SourceCache, layer: BackgroundStyleLayer, coords: Array<OverscaledTileID>, renderFlags: RenderFlags) {
export function drawBackground(painter: Painter, sourceCache: SourceCache, layer: BackgroundStyleLayer, coords: Array<OverscaledTileID>, renderFlags: RenderOptions) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Don't forget to change the parameter name as well - renderOptions...

@HarelM
Copy link
Collaborator

HarelM commented Nov 12, 2024

LGTM, thanks!

@@ -47,7 +47,7 @@ export function drawBackground(painter: Painter, sourceCache: SourceCache, layer
for (const tileID of tileIDs) {
const projectionData = transform.getProjectionData({
overscaledTileID: tileID,
ignoreGlobeMatrix: globeWithTerrain
applyGlobeMatrix: !isRenderingToTexture
Copy link
Member

@birkskyum birkskyum Nov 12, 2024

Choose a reason for hiding this comment

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

is an applyTerrainMatrix: true missing here.

@@ -80,7 +81,7 @@ export function drawCircles(painter: Painter, sourceCache: SourceCache, layer: C
const terrainData = painter.style.map.terrain && painter.style.map.terrain.getTerrainData(coord);
const uniformValues = circleUniformValues(painter, tile, layer, translateForUniforms, radiusCorrectionFactor);

const projectionData = transform.getProjectionData({overscaledTileID: coord});
const projectionData = transform.getProjectionData({overscaledTileID: coord, applyGlobeMatrix: !isRenderingToTexture});
Copy link
Member

@birkskyum birkskyum Nov 12, 2024

Choose a reason for hiding this comment

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

Is an applyTerrainMatrix missing here too?

const projectionData = transform.getProjectionData({
overscaledTileID: coord,
ignoreGlobeMatrix: globeWithTerrain
applyGlobeMatrix: !isRenderingToTexture
Copy link
Member

Choose a reason for hiding this comment

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

Here also, I'd expect applyTerrainMatrix: true

const projectionData = transform.getProjectionData({
overscaledTileID: coord,
aligned: align,
ignoreGlobeMatrix: globeWithTerrain
applyGlobeMatrix: !isRenderingToTexture
Copy link
Member

@birkskyum birkskyum Nov 12, 2024

Choose a reason for hiding this comment

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

here too, I expected an additional applyTerrainMatrix: true

@birkskyum birkskyum mentioned this pull request Nov 13, 2024
2 tasks
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.

4 participants