ThinkGeo.com    |     Documentation    |     Premium Support

GPU renderer: what still needs the classic fallback

ThinkGeo.Gpu 15.0.0-beta154. Thanks for the beta140–154 fixes — OffsetFromLine , underline/strikeout/Black, fillPattern , icon , DashArray.FromGeoPen and the visibility fix all work for us now. These are the remaining cases where we still have to switch the whole scene back to the classic renderer, or work around the SDK.

1. Area outline loses its pixel offset When an AreaStyle has XOffsetInPixel / YOffsetInPixel and its outline is translated as a separate line layer (outline wider than one pixel, dashed, or no fill), the translator passes 0, 0 as the line offset. The fill moves, the outline stays. No warning is reported. Ask: pass the offsets to the outline layer too, or report a warning.

2. Hatch pens are flattened A GeoPen with a GeoHatchBrush becomes a solid line in the hatch’s background colour. With a transparent background the line disappears. No warning is reported. Ask: either a warning like the one for area fills, or a pattern stroke.

3. Direction points, text masks, rotated labels The translator reports these as “no GPU translation”. Any layer using them sends the whole scene to the classic renderer. Ask: translations for LineStyle.DirectionPointStyle , TextStyle.Mask and RotationAngle . Masks (a filled box behind the text) are the most common one for us.

4. Changing the number of vector sources needs a new host SetStyleAsync refuses a style whose vector-source count differs from the one the map opened with ("[GpuRebind] refused: style declares N vector sources, map opened with M"). Adding or removing one translated layer therefore means rebuilding the host and reopening all readers. Ask: let a style add or remove sources on an open host, keeping the cached tiles of the sources that did not change.

5. VectorPmTilesGenerator is not safe to run twice at once The generator uses one static feature dictionary for the whole process. It is cleared at the start of each run and read without a lock during tile generation. Two generations in parallel corrupt each other. Our workaround: a process-wide gate so only one generation runs at a time. Related: the generation grid ends at zoom 19. Finer display scales overzoom the archive. Ask: keep the cache per generation, and allow zoom 20+.

Smaller notes:

  • Parallel tile-cache generation ( Layer.GenerateTileCacheAsync ) only clones layers that are closed. Documenting this would save others a search.
  • We still call GdalManager.ConfigureGdal() / ConfigureOgr() at startup as the temporary fix for the GDAL crash you were working on. Is that fixed in a current beta, so we can remove the call?

Hi Julian,

15.0.0-beta155 is up and has three of the following five.

  1. Area outline loses its pixel offset — fixed.
    The fill paint always carried the offsets; the separate outline layer was emitted with 0, 0. It now takes the same offsets.

  2. Hatch pens are flattened — now reported.
    It is the warning, because the engine has no line-pattern at all — a line layer has a color, a width and a dash, and nothing to stroke a pattern with. So the translation says what it dropped:

<layer>: LineStyle strokes with a hatch brush, which has no GPU translation; the stroke draws in the hatch's background colour.

The transparent-background case you mention was worse than silent — the pen read as “no ink” and the layer was never created at all. That one now warns and emits nothing, deliberately, rather than adding an invisible layer.

One related change worth knowing about: a one-pixel hatch pen used to become fill-outline-color, which drew it in the pen’s own color rather than anything the hatch strokes with. It is now a line layer like any other hatch pen, and warns.

  1. Direction points, text masks, rotated labels — still open.
    We’ll work on the masks first (as you said they are the most common one for you), and then direction points and rotated labels.

  2. Changing the number of vector sources — fixed.
    A longer or shorter list is a rebind now. Only the positions past the shorter of the two lists are arriving or leaving; the ones both lists share keep their open connections and their decoded tiles, so the sources that did not change hold still while yours appears over them. You should not need to rebuild the host or reopen readers for this anymore.

Two refusals remain, and they throw InvalidOperationException instead of writing a trace line and carrying on: a source arriving on a different tile grid, and a style with no vector source at all. Neither has a meaning to give the tiles already in flight. SetStyleAsync now takes the new document only after the rebind has agreed to it, so a call that throws leaves the map showing what it showed before, rather than the new cartography over the old data — which is what the old trace-and-continue produced.

  1. VectorPmTilesGenerator is not safe to run twice — confirmed, not yet fixed.
    You are right. It’s something we need to do, and we’ll make it happen in the next beta.

On the two smaller notes:

The closed-layer rule is already documented, as of beta143 — TileCacheGenerationOptions.MaxConcurrency says “a layer that is open, or cannot be cloned, stays shared and is drawn under its lock”. If that is not where you looked, tell us where you did and we will put it there too.

Keep GdalManager.ConfigureGdal(). It is not a workaround we have retired. The failure is one of load order: if another product’s gdal.dll — QGIS or OSGeo4W on the PATH — enters the process before we initialise, name-based binding resolves to it and nothing we do afterwards can win. The permanent fix is renaming our own core native so the collision cannot happen, and that means rebuilding the native pipeline; it is not done. The call costs nothing, so leave it in.

I’ll keep you posted here.

Thanks,
Ben

1 Like

Hi Ben, I feel like I need to write my appreciation at this point. Thanks for your quick responses and fixes! It’s super fun to work with you and the framework :grin:

Hi Julian,

The appreciation is mine! Thanks for testing and for the feedback — it’s been unusually precise, which is why the fixes came fast.

And here, 15.0.0-beta156 is up with the two that were open.

Direction points, text masks, rotated labels — added.

  • Masks. The mask’s fill is drawn once as a sprite and fitted to the text with MaskMargin as the padding — the icon-text-fit the layout already had. The fill alone: a stretched box stretches its border with it, so a mask with an outline draws as its fill and warns, until we can scale the image in nine slices. A rounded or circular mask draws as a rectangle and warns.

  • Direction points. A line-placed symbol layer: the DirectionPointStyle drawn once as a sprite, spaced by DirectionPointInterval, turned with the line, never turned upright. The sprite is drawn with the style’s own RotationAngle cleared — the classic renderer overwrites that angle per segment anyway — so the art is expected to point along the positive x axis. The placement is not the classic recursive one; on a straight line the points land in the same places, on a bent one close to them, and these are collision-aware.

  • Rotated labels. There was no text-rotate in the GPU engine at all, so this is new rather than translated: SymbolLayout.TextRotateDegrees, through the style document, the placement, the collision box and the glyph quads. A point label’s RotationAngle becomes it with the sign turned (classic is counter-clockwise for a positive angle, text-rotate is clockwise), so a classic 30 lands where it did, and a mask turns with the text. Two limits: a label that follows a line still warns — it is turned by the line in both renderers — and underline/strikeout on a rotated label draw unrotated.

VectorPmTilesGenerator — fixed.

  • Each generation cuts from a concurrent cache of its own, handed down the call chain. The MBTiles generator had the same shape behind a thread-safe cot bug — its cache was keyed by the layer’s name, so two generations at once whose layers shared a name cut each other’s features — and it is per-generation now too. You can drop the process-wide gate.

  • The zoom-19 ceiling was a hand-written switch over the twenty named zoom levels; the ladder is geometric, so it extrapolates. Lifting it exposed what the writers never checked: PMTiles addrilbert curve), MBTiles tile coordinates overflow at31. Each generator now refuses a MaximumZoom past its limit — 26 and 30 — with ArgumentOutOfRangeException before a single tile is cut, rather than writing an archive it could not read back.

Two things not on your list, also in beta156.

  • The sprite a point style is registered as is now measured rather than sized from SymbolSize — nested CustomPointStyles, multi-character glyphs, mask margins, rotation and offsets all get the room they draw into, so Images.Add(name, pointStyle) no longer crops and your own rasterise-then-crop path can go.

  • A viewport-aligned icon now honors icon-rotate; it used to ignore it, which is why a mask could not turn with its label.

One correction for your side: the sprite path was applying a point style’s pixel offsets twice (drawn in, then named on the layout again) — that was fixed in beta155, so if you compensated for it, take the compensation out.

Just FYI, most of the items here overlaps with the ones in GPU highlight parity and live source changes, I’ll make sure all the items are covered and reply there.

Thanks,
Ben