drm: Handle the same fb_id being held more than once

Ref this properly -- this can happen when a window is recreated sometimes
it seems.
This commit is contained in:
Joshua Ashton 2021-12-17 10:25:45 +00:00 committed by Pierre-Loup A. Griffais
parent 50ee712429
commit be1a784278
2 changed files with 28 additions and 27 deletions

View file

@ -201,7 +201,6 @@ static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsi
assert( previous_fbid != 0 );
struct fb &previous_fb = get_fb( g_DRM, previous_fbid );
assert( previous_fb.n_refs > 0 );
if ( --previous_fb.n_refs == 0 )
{
@ -791,7 +790,7 @@ int drm_commit(struct drm_t *drm, struct Composite_t *pComposite, struct VulkanP
for ( uint32_t i = 0; i < drm->fbids_in_req.size(); i++ )
{
struct fb &fb = get_fb( g_DRM, drm->fbids_in_req[ i ] );
assert( fb.held == true );
assert( fb.held_refs );
fb.n_refs++;
}
@ -913,10 +912,11 @@ uint32_t drm_fbid_from_dmabuf( struct drm_t *drm, struct wlr_buffer *buf, struct
/* Nested scope so fb doesn't end up in the out: label */
{
struct fb &fb = get_fb( *drm, fb_id );
assert( fb.held == false );
assert( fb.held_refs == 0 );
fb.id = fb_id;
fb.buf = buf;
fb.held = !buf;
if (!buf)
fb.held_refs++;
fb.n_refs = 0;
}
@ -948,15 +948,14 @@ out:
void drm_drop_fbid( struct drm_t *drm, uint32_t fbid )
{
struct fb &fb = get_fb( *drm, fbid );
assert( fb.held == false ||
assert( fb.held_refs == 0 ||
fb.buf == nullptr );
fb.held = false;
fb.held_refs = 0;
if ( fb.n_refs != 0 )
if ( fb.n_refs != 0 )
{
std::lock_guard<std::mutex> lock( drm->free_queue_lock );
drm->fbid_free_queue.push_back( fbid );
return;
}
@ -969,7 +968,7 @@ void drm_drop_fbid( struct drm_t *drm, uint32_t fbid )
static void drm_unlock_fb_internal( struct drm_t *drm, struct fb *fb )
{
assert( !fb->held );
assert( fb->held_refs == 0 );
assert( fb->n_refs == 0 );
if ( fb->buf != nullptr )
@ -983,15 +982,16 @@ static void drm_unlock_fb_internal( struct drm_t *drm, struct fb *fb )
void drm_lock_fbid( struct drm_t *drm, uint32_t fbid )
{
struct fb &fb = get_fb( *drm, fbid );
assert( fb.held == false );
assert( fb.n_refs == 0 );
fb.held = true;
if ( fb.buf != nullptr )
if ( fb.held_refs++ == 0 )
{
wlserver_lock();
wlr_buffer_lock( fb.buf );
wlserver_unlock();
if ( fb.buf != nullptr )
{
wlserver_lock();
wlr_buffer_lock( fb.buf );
wlserver_unlock();
}
}
}
@ -999,21 +999,20 @@ void drm_unlock_fbid( struct drm_t *drm, uint32_t fbid )
{
struct fb &fb = get_fb( *drm, fbid );
assert( fb.held == true );
fb.held = false;
assert( fb.held_refs > 0 );
if ( --fb.held_refs != 0 )
return;
if ( fb.n_refs == 0 )
{
/* FB isn't being used in any page-flip, free it immediately */
drm_verbose_log.debugf("free fbid %u", fbid);
drm_unlock_fb_internal( drm, &fb );
}
else
if ( fb.n_refs != 0 )
{
std::lock_guard<std::mutex> lock( drm->free_queue_lock );
drm->fbid_unlock_queue.push_back( fbid );
return;
}
/* FB isn't being used in any page-flip, free it immediately */
drm_verbose_log.debugf("free fbid %u", fbid);
drm_unlock_fb_internal( drm, &fb );
}
/* Prepares an atomic commit without using libliftoff */

View file

@ -54,8 +54,10 @@ struct fb {
uint32_t id;
/* Client buffer, if any */
struct wlr_buffer *buf;
/* A FB is held if it's being used by steamcompmgr */
bool held;
/* A FB is held if it's being used by steamcompmgr
* doesn't need to be atomic as it's only ever
* modified/read from the steamcompmgr thread */
int held_refs;
/* Number of page-flips using the FB */
std::atomic< uint32_t > n_refs;
};