Use FB_DAMAGE_CLIPS instead of drmModeDirtyFB()

This commit is contained in:
Cameron Gutman
2026-01-11 01:15:28 -06:00
parent 3ea62c0800
commit 88719cc8bf
2 changed files with 70 additions and 18 deletions

View File

@@ -1480,25 +1480,15 @@ void DrmRenderer::blitOverlayToCompositionSurface(Overlay::OverlayType type, SDL
}
}
// Dirty the modified portion of the FB
drmModeClip clip;
clip.x1 = overlayUnionRect.x;
clip.x2 = overlayUnionRect.x + overlayUnionRect.w;
clip.y1 = overlayUnionRect.y;
clip.y2 = overlayUnionRect.y + overlayUnionRect.h;
drmModeDirtyFB(m_DrmFd, m_OverlayCompositionSurfaceFbId, &clip, 1);
// Dirty the modified portion of the plane
m_PropSetter.damagePlane(m_OverlayPlanes[0], overlayUnionRect);
}
else {
// Clear the pixels where this overlay was drawn before
SDL_FillRect(m_OverlayCompositionSurface, &m_OverlayRects[type], 0);
// Dirty the modified portion of the FB
drmModeClip clip;
clip.x1 = m_OverlayRects[type].x;
clip.x2 = m_OverlayRects[type].x + m_OverlayRects[type].w;
clip.y1 = m_OverlayRects[type].y;
clip.y2 = m_OverlayRects[type].y + m_OverlayRects[type].h;
drmModeDirtyFB(m_DrmFd, m_OverlayCompositionSurfaceFbId, &clip, 1);
// Dirty the modified portion of the plane
m_PropSetter.damagePlane(m_OverlayPlanes[0], m_OverlayRects[type]);
}
}

View File

@@ -213,6 +213,8 @@ class DrmRenderer : public IFFmpegRenderer {
// Atomic only
uint32_t pendingFbId;
uint32_t pendingDumbBuffer;
uint32_t fbDamageClipsPropId;
std::vector<drm_mode_rect> pendingFbDamageRects;
bool modified;
};
@@ -270,7 +272,7 @@ class DrmRenderer : public IFFmpegRenderer {
}
}
bool set(const DrmProperty& prop, uint64_t value, bool verbose = true) {
int set(uint32_t objectId, uint32_t objectType, uint32_t propId, uint64_t value) {
int err;
if (m_Atomic) {
@@ -281,7 +283,7 @@ class DrmRenderer : public IFFmpegRenderer {
m_AtomicReq = drmModeAtomicAlloc();
}
err = drmModeAtomicAddProperty(m_AtomicReq, prop.objectId(), prop.id(), value);
err = drmModeAtomicAddProperty(m_AtomicReq, objectId, propId, value);
// This returns the new count of properties on success,
// so normalize it to 0 like drmModeObjectSetProperty()
@@ -290,9 +292,14 @@ class DrmRenderer : public IFFmpegRenderer {
}
}
else {
err = drmModeObjectSetProperty(m_Fd, prop.objectId(), prop.objectType(), prop.id(), value);
err = drmModeObjectSetProperty(m_Fd, objectId, objectType, propId, value);
}
return err;
}
bool set(const DrmProperty& prop, uint64_t value, bool verbose = true) {
int err = set(prop.objectId(), prop.objectType(), prop.id(), value);
if (verbose && err == 0) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Set property '%s': %" PRIu64,
@@ -440,6 +447,26 @@ class DrmRenderer : public IFFmpegRenderer {
}
}
// The damage rect is relative to the FB
void damagePlane(const DrmPropertyMap& plane, const SDL_Rect& rect) {
SDL_assert(m_Atomic);
if (auto prop = plane.property("FB_DAMAGE_CLIPS")) {
std::lock_guard lg { m_Lock };
auto& pb = m_PlaneBuffers[plane.objectId()];
// Append this new damage rect to our existing list
drm_mode_rect drmRect;
drmRect.x1 = rect.x;
drmRect.x2 = rect.x + rect.w;
drmRect.y1 = rect.y;
drmRect.y2 = rect.y + rect.h;
pb.pendingFbDamageRects.emplace_back(std::move(drmRect));
pb.fbDamageClipsPropId = prop->id();
}
}
bool testPlane(const DrmPropertyMap& plane,
uint32_t crtcId, uint32_t fbId,
int32_t crtcX, int32_t crtcY,
@@ -500,11 +527,41 @@ class DrmRenderer : public IFFmpegRenderer {
drmModeAtomicReqPtr req = nullptr;
std::unordered_map<uint32_t, PlaneBuffer> pendingBuffers;
std::vector<uint32_t> damageBlobIds;
{
std::lock_guard lg { m_Lock };
// Create property blobs for any pending FB damage clip rects
for (auto &[planeId, pb] : m_PlaneBuffers) {
uint32_t damageBlob;
if (!pb.pendingFbDamageRects.empty()) {
int err = drmModeCreatePropertyBlob(m_Fd,
pb.pendingFbDamageRects.data(),
pb.pendingFbDamageRects.size() * sizeof(drm_mode_rect),
&damageBlob);
if (err < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"drmModeCreatePropertyBlob(FB_DAMAGE_CLIPS) failed: %d",
err);
continue;
}
err = set(planeId, DRM_MODE_OBJECT_PLANE, pb.fbDamageClipsPropId, damageBlob);
if (err < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed to set property 'FB_DAMAGE_CLIPS': %d",
err);
// Fall-through
}
damageBlobIds.emplace_back(damageBlob);
}
}
// Take ownership of the current atomic request to commit it and
// allow other threads to queue up changes for the next one.
std::lock_guard lg { m_Lock };
std::swap(req, m_AtomicReq);
std::swap(pendingBuffers, m_PlaneBuffers);
}
@@ -541,6 +598,11 @@ class DrmRenderer : public IFFmpegRenderer {
err);
}
// Free the damage clip blobs
for (auto blobId : damageBlobIds) {
drmModeDestroyPropertyBlob(m_Fd, blobId);
}
// Update the buffer state for any modified planes
std::lock_guard lg { m_Lock };
for (auto it = pendingBuffers.begin(); it != pendingBuffers.end(); it++) {