Adding a few more people on CC. On 6/24/26 19:55, Harry Wentland wrote: > On 2026-06-24 11:52, Christian König wrote: >> 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? >> > > DCN can't switch between mapped and unmapped memory. I'm not a memory > management expert but wouldn't GTT be in GART (mapped) and VRAM in > the (unmapped) FB aperture?
Well at the moment yes, but that is changeable. It's correct that for scanout we currently access GTT buffers "mapped" through the GART while VRAM buffers are accessed "unmapped" through the FB aperture. As far as I know starting with I think Vega or Navi 1x (or maybe Navi 2x/3x you probably know that better than me) the DCN block became capable of scanning out through the GART as well, which is a prerequisite that we can allocate framebuffers on APUs in GTT in the first place. So what we could do in theory is to allocate a window in the GART address space, map the VRAM buffer into it and then start scanning out from that address instead. We already do that for a couple of workarounds on older HW and to copy TMZ buffers etc... So most of the infrastructure necessary is now already there. This would also reduce the pressure on the VRAM manager backend because we don't need to allocate those buffers contigiously any more. Leading to less pin failed with -12 errors when memory becomes tight. The only problem I see is that I don't know if this doesn't have any negative effect on the DCN power consumption or something like that? That's where I need input from the display team. Additional to that we need to find somebody who implements/tests that stuff, but maybe Timur or somebody else from Valve could take that since I think. Regards, Christian. > > From DCHUB HW doc: > "No change from mapped to unmapped or unmapped to mapped is > allowed for immediate f lip" > > If so, we can't async flip between them. > > Harry > >> 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); >>>> >>> >> >
