OpenTTD / OpenTTD/OpenTTD

Incorrect size bounds checks in vehicle viewport hash scan in ViewportAddVehicles

Open
#6,618 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug flyspray
Dominant language
C++
Stars
8.3k
Forks
1.3k
Avg merge
1d 20h
Merged PRs (30d)
37

Description

JGR opened the ticket and wrote:

In ViewportAddVehicles in src/vehicle.cpp there are bounds checks:

if (dpi->width + (70 * ZOOM_LVL_BASE) < (1 << (7 + 6 + ZOOM_LVL_SHIFT))) {
if (dpi->height + (70 * ZOOM_LVL_BASE) < (1 << (6 + 6 + ZOOM_LVL_SHIFT))) {

These are to prevent the extent of the untruncated span from xl to xu and yl to yu from being unable to fit in the hash bit allocation (6 bits each).

In the case of width, in the case where the lower 9 bits of (l - (70 * ZOOM_LVL_BASE)) are greater than the lower 9 bits of r,
dpi->width + (70 * ZOOM_LVL_BASE) can be less than (1 << (7 + 6 + ZOOM_LVL_SHIFT)) even when the the untruncated hash values differ by 0x40, such that the truncated values are the same.
This has the effect that if the viewport re-draw area is the right size and offset, the iteration over the vehicle viewport hash only finds vehicles at the two edges but not in the middle.
This can visually manifest as flickering effects.

To give a concrete example:
Noting that: ZOOM_LVL_BASE = 4, ZOOM_LVL_SHIFT = 2
If: dpi->left = 0x317, dpi->width = 0x7CE9
Then:
dpi->width + (70 * ZOOM_LVL_BASE) = 0x7E01
(1 << (7 + 6 + ZOOM_LVL_SHIFT)) = 0x8000
dpi->width + (70 * ZOOM_LVL_BASE) < (1 << (7 + 6 + ZOOM_LVL_SHIFT)) evaluates to true
l - (70 * ZOOM_LVL_BASE) = 0x1FF, r = 0x8000
xl = 0, xu = 0
Consequently: only vehicles in hash row 0 will be drawn, even though the viewport redraw covers the whole width of the viewport hash

A possible solution for width/x would be to perform the bounds check after doing the shift-right by 9, but before truncating to 6 bits.

Height/y is the same except the shift is by 8 instead of 9.

Reported version: trunk
Operating system: All


This issue was imported from FlySpray: https://bugs.openttd.org/task/6618

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/vehicle.cpp at ViewportAddVehicles and inspect the width and height bounds checks around the vehicle viewport hash scan. Work through the supplied width example and compare the checks with the stated shifts before changing anything. Done means the scan covers the full redraw area without missing vehicles at intermediate hash rows or columns, including the analogous height case.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
computer-graphics, game-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.