On 6/24/26 17:30, Harry Wentland wrote: > On 2026-06-16 03:31, Christian König wrote: >> On 6/16/26 09:10, Matthew Schwartz wrote: >>> Native scanout buffers on APUs are pinned with the VRAM|GTT domain, so >>> under VRAM carveout pressure a swapchain can end up split across VRAM and >>> GTT. The scanout buffer's memory type then changes from one flip to the >>> next, and amdgpu_dm_crtc_mem_type_changed() rejects an async page flip >>> across the change. The result is repeated async page flip failures, >>> observed as choppy updates under carveout pressure, until the buffers >>> reconverge to a single domain. >> >> That's intentional behavior. >> >>> Pin native scanout buffers in VRAM only so the swapchain stays in one >>> memory domain. Restrict this to APUs whose carveout is larger than > > Above you mention that under VRAM pressure a swapchain can end up split > across VRAM and GTT. Wouldn't restricting the swapchain to VRAM now mean > that in those cases you fail to allocate the swapchain entirely?
Yes, exactly that. My educated guess is that the display server then falls back to using a copy instead of a flip and that helps saving memory somehow (e.g. less scanout buffers alocated concurrently). Would it somehow be possible to get DC to dynamically switch between VRAM and GTT? Regards, Christian > > Harry > >>> AMDGPU_SG_THRESHOLD, so small-carveout parts keep their existing VRAM|GTT >>> placement, and fall back to GTT when the buffer does not fit in VRAM, so >>> the flip still succeeds and the swapchain stays in one domain. Imported >>> buffers may only be pinnable in GTT, so leave those on the default >>> domains. >> >> The display guys need to take a closer look at that, but it sounds like what >> we used to have before and that caused problems. >> >> We somehow need to change the DC stuff to allow switching between VRAM and >> GTT frame buffers to fully fix this. >> >> Regards, >> Christian. >> >>> >>> Signed-off-by: Matthew Schwartz <[email protected]> >>> --- >>> Hi, >>> >>> This came up while testing my kernel patch to fix mem_type detection for >>> async flips here: >>> https://lore.kernel.org/amd-gfx/[email protected]/ >>> >>> I found a new issue where splitting a swapchain between VRAM and GTT >>> causes a noticeable stutter in gameplay if gamescope is using direct >>> scanout and tearing is enabled while a game is already running. >>> >>> Once a swapchain is split across the VRAM carveout and GTT, the scanout >>> buffer's mem_type changes from one flip to the next, so >>> amdgpu_dm_crtc_mem_type_changed() rejects the async flip. Under direct >>> scanout with tearing that rejection recurs every time the displayed buffer >>> crosses domains, which is what surfaces as the choppiness. >>> >>> With this patch, I can enable tearing on top of an already-disabled frame >>> limit mid-game and no longer reproduce the choppiness. >>> >>> amdgpu_gem_info confirms the swapchain converges to a single domain >>> instead of splitting across VRAM and GTT. >>> >>> Before: >>> 0x00000f81: 3981312 byte GTT exported as ino:275 NO_CPU_ACCESS >>> CPU_GTT_USWC VRAM_CLEARED VRAM_CONTIGUOUS EXPLICIT_SYNC write >>> fence:drm_sched gfx_0.0.0 seq 88248 signalled >>> 0x00000f82: 3981312 byte GTT exported as ino:276 NO_CPU_ACCESS >>> CPU_GTT_USWC VRAM_CLEARED VRAM_CONTIGUOUS EXPLICIT_SYNC write >>> fence:drm_sched gfx_0.0.0 seq 88224 signalled >>> 0x00000f83: 3981312 byte VRAM VISIBLE pin count 1 exported as ino:277 >>> NO_CPU_ACCESS CPU_GTT_USWC VRAM_CLEARED VRAM_CONTIGUOUS EXPLICIT_SYNC >>> write fence:drm_sched gfx_0.0.0 seq 88236 signalled >>> >>> After: >>> 0x00000f82: 3981312 byte VRAM VISIBLE pin count 1 exported as ino:548 >>> NO_CPU_ACCESS CPU_GTT_USWC VRAM_CLEARED VRAM_CONTIGUOUS EXPLICIT_SYNC >>> write fence:drm_sched gfx_0.0.0 seq 822258 signalled >>> 0x00000f83: 3981312 byte VRAM VISIBLE exported as ino:549 >>> NO_CPU_ACCESS CPU_GTT_USWC VRAM_CLEARED VRAM_CONTIGUOUS EXPLICIT_SYNC >>> write fence:drm_sched gfx_0.0.0 seq 822255 signalled >>> 0x00000f84: 3981312 byte VRAM VISIBLE exported as ino:550 >>> NO_CPU_ACCESS CPU_GTT_USWC VRAM_CLEARED VRAM_CONTIGUOUS EXPLICIT_SYNC >>> write fence:drm_sched gfx_0.0.0 seq 822261 signalled >>> >>> Does this seem like the correct approach to take for fixing the observed >>> issue? I wanted to start with an RFC to make sure I didn't overlook >>> anything obvious or miss any better methods of fixing this. >>> >>> Thanks, >>> Matt >>> --- >>> .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 29 +++++++++++++++++-- >>> 1 file changed, 26 insertions(+), 3 deletions(-) >>> >>> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c >>> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c >>> index 23a9faa2ea89..b99f938e58ec 100644 >>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c >>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c >>> @@ -932,6 +932,7 @@ static int amdgpu_dm_plane_helper_prepare_fb(struct >>> drm_plane *plane, >>> struct amdgpu_bo *rbo; >>> struct dm_plane_state *dm_plane_state_new, *dm_plane_state_old; >>> uint32_t domain; >>> + bool pin_vram_only; >>> int r; >>> >>> if (!new_state->fb) { >>> @@ -958,13 +959,35 @@ static int amdgpu_dm_plane_helper_prepare_fb(struct >>> drm_plane *plane, >>> if (r) >>> goto error_unlock; >>> >>> - if (plane->type != DRM_PLANE_TYPE_CURSOR) >>> - domain = amdgpu_display_supported_domains(adev, rbo->flags); >>> - else >>> + /* >>> + * Pin native scanout in VRAM on APUs so a swapchain stays in one >>> + * memory domain. A VRAM/GTT split changes its mem_type between flips >>> + * and amdgpu_dm_crtc_mem_type_changed() rejects the async flip. Skip >>> + * small carveouts that may not fit, and imported buffers. >>> + */ >>> + pin_vram_only = plane->type != DRM_PLANE_TYPE_CURSOR && >>> + (adev->flags & AMD_IS_APU) && >>> + !rbo->tbo.base.import_attach && >>> + adev->gmc.real_vram_size > AMDGPU_SG_THRESHOLD; >>> + >>> + if (plane->type == DRM_PLANE_TYPE_CURSOR || pin_vram_only) >>> domain = AMDGPU_GEM_DOMAIN_VRAM; >>> + else >>> + domain = amdgpu_display_supported_domains(adev, rbo->flags); >>> >>> rbo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; >>> r = amdgpu_bo_pin(rbo, domain); >>> + if (r == -ENOMEM && pin_vram_only) { >>> + /* >>> + * VRAM could not fit the buffer. Fall back to GTT where >>> + * allowed so the swapchain stays in one domain. >>> + */ >>> + domain = amdgpu_display_supported_domains(adev, rbo->flags); >>> + if (domain & AMDGPU_GEM_DOMAIN_GTT) { >>> + domain = AMDGPU_GEM_DOMAIN_GTT; >>> + r = amdgpu_bo_pin(rbo, domain); >>> + } >>> + } >>> if (unlikely(r != 0)) { >>> if (r != -ERESTARTSYS) >>> DRM_ERROR("Failed to pin framebuffer with error %d\n", >>> r); >> >
