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);
>>
> 

Reply via email to