15.03.2021 01:31, Michał Mirosław пишет: > On Thu, Mar 11, 2021 at 08:22:54PM +0300, Dmitry Osipenko wrote: >> Display controller (DC) performs isochronous memory transfers, and thus, >> has a requirement for a minimum memory bandwidth that shall be fulfilled, >> otherwise framebuffer data can't be fetched fast enough and this results >> in a DC's data-FIFO underflow that follows by a visual corruption. > [...] >> +static unsigned long >> +tegra_plane_overlap_mask(struct drm_crtc_state *state, >> + const struct drm_plane_state *plane_state) >> +{ >> + const struct drm_plane_state *other_state; >> + const struct tegra_plane *tegra; >> + unsigned long overlap_mask = 0; >> + struct drm_plane *plane; >> + struct drm_rect rect; >> + >> + if (!plane_state->visible || !plane_state->fb) >> + return 0; >> + >> + drm_atomic_crtc_state_for_each_plane_state(plane, other_state, state) { > [...] >> + /* >> + * Data-prefetch FIFO will easily help to overcome temporal memory >> + * pressure if other plane overlaps with the cursor plane. >> + */ >> + if (tegra_plane_is_cursor(plane_state) && overlap_mask) >> + return 0; >> + >> + return overlap_mask; >> +} > > Since for cursor plane this always returns 0, you could test > tegra_plane_is_cursor() at the start of the function. Yes, thanks. >> +static int tegra_crtc_calculate_memory_bandwidth(struct drm_crtc *crtc, >> + struct drm_atomic_state *state) > [...] >> + /* >> + * For overlapping planes pixel's data is fetched for each plane at >> + * the same time, hence bandwidths are accumulated in this case. >> + * This needs to be taken into account for calculating total bandwidth >> + * consumed by all planes. >> + * >> + * Here we get the overlapping state of each plane, which is a >> + * bitmask of plane indices telling with what planes there is an >> + * overlap. Note that bitmask[plane] includes BIT(plane) in order >> + * to make further code nicer and simpler. >> + */ >> + drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, new_state) { >> + tegra_state = to_const_tegra_plane_state(plane_state); >> + tegra = to_tegra_plane(plane); >> + >> + if (WARN_ON_ONCE(tegra->index >= TEGRA_DC_LEGACY_PLANES_NUM)) >> + return -EINVAL; >> + >> + plane_peak_bw[tegra->index] = tegra_state->peak_memory_bandwidth; >> + mask = tegra_plane_overlap_mask(new_state, plane_state); >> + overlap_mask[tegra->index] = mask; >> + >> + if (hweight_long(mask) != 3) >> + all_planes_overlap_simultaneously = false; >> + } >> + >> + old_state = drm_atomic_get_old_crtc_state(state, crtc); >> + old_dc_state = to_const_dc_state(old_state); >> + >> + /* >> + * Then we calculate maximum bandwidth of each plane state. >> + * The bandwidth includes the plane BW + BW of the "simultaneously" >> + * overlapping planes, where "simultaneously" means areas where DC >> + * fetches from the planes simultaneously during of scan-out process. >> + * >> + * For example, if plane A overlaps with planes B and C, but B and C >> + * don't overlap, then the peak bandwidth will be either in area where >> + * A-and-B or A-and-C planes overlap. >> + * >> + * The plane_peak_bw[] contains peak memory bandwidth values of >> + * each plane, this information is needed by interconnect provider >> + * in order to set up latency allowness based on the peak BW, see >> + * tegra_crtc_update_memory_bandwidth(). >> + */ >> + for (i = 0; i < ARRAY_SIZE(plane_peak_bw); i++) { >> + overlap_bw = 0; >> + >> + for_each_set_bit(k, &overlap_mask[i], 3) { >> + if (k == i) >> + continue; >> + >> + if (all_planes_overlap_simultaneously) >> + overlap_bw += plane_peak_bw[k]; >> + else >> + overlap_bw = max(overlap_bw, plane_peak_bw[k]); >> + } >> + >> + new_dc_state->plane_peak_bw[i] = plane_peak_bw[i] + overlap_bw; >> + >> + /* >> + * If plane's peak bandwidth changed (for example plane isn't >> + * overlapped anymore) and plane isn't in the atomic state, >> + * then add plane to the state in order to have the bandwidth >> + * updated. >> + */ >> + if (old_dc_state->plane_peak_bw[i] != >> + new_dc_state->plane_peak_bw[i]) { >> + plane = tegra_crtc_get_plane_by_index(crtc, i); >> + if (!plane) >> + continue; >> + >> + plane_state = drm_atomic_get_plane_state(state, plane); >> + if (IS_ERR(plane_state)) >> + return PTR_ERR(plane_state); >> + } >> + } > [...] > > Does it matter to which channel (plane) the peak bw is attached? Would > it still work if the first channel specified max(peak_bw of overlaps) > and others only zeroes? The latency allowance will be configured incorrectly for the case of zeroes by the memory driver, hence it does matter. >> + /* >> + * Horizontal downscale needs a lower memory latency, which roughly >> + * depends on the scaled width. Trying to tune latency of a memory >> + * client alone will likely result in a strong negative impact on >> + * other memory clients, hence we will request a higher bandwidth >> + * since latency depends on bandwidth. This allows to prevent memory >> + * FIFO underflows for a large plane downscales, meanwhile allowing >> + * display to share bandwidth fairly with other memory clients. >> + */ >> + if (src_w > dst_w) >> + mul = (src_w - dst_w) * bpp / 2048 + 1; >> + else >> + mul = 1; > [...] > > One point is unexplained yet: why is the multiplier proportional to a > *difference* between src and dst widths? Also, I would expect max (worst > case) is pixclock * read_size when src_w/dst_w >= read_size. IIRC, the difference gives a more adequate/practical result than the proportion. Although, downstream driver uses proportion. I'll try to revisit this for the next version of the patch. > BTW, you could move this below and : if (src > dst_w) peak_bandwidth *= ... Indeed, and should be a bit nicer to use 'mul' in both cases. _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel