From 30bfd48d8ee3843ba55a0ad2e598580badce4c00 Mon Sep 17 00:00:00 2001 From: jarvis Date: Sat, 29 Jul 2023 16:35:53 -0400 Subject: [PATCH 1/3] Enable atomic commits for DRM rendering Signed-off: Peyton Howe --- picamera2/previews/drm_preview.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/picamera2/previews/drm_preview.py b/picamera2/previews/drm_preview.py index f6376d67..74419e28 100644 --- a/picamera2/previews/drm_preview.py +++ b/picamera2/previews/drm_preview.py @@ -193,13 +193,13 @@ def render_drm(self, picam2, completed_request): self.drmfbs[fb] = drmfb drmfb = self.drmfbs[fb] - self.crtc.set_plane(self.plane, drmfb, x, y, w, h, 0, 0, width, height) - # An "atomic commit" would probably be better, but I can't get this to work... - # ctx = pykms.AtomicReq(self.card) - # ctx.add(self.plane, {"FB_ID": drmfb.id, "CRTC_ID": self.crtc.id, - # "SRC_W": width << 16, "SRC_H": height << 16, - # "CRTC_X": x, "CRTC_Y": y, "CRTC_W": w, "CRTC_H": h}) - # ctx.commit() + # self.crtc.set_plane(self.plane, drmfb, x, y, w, h, 0, 0, width, height) + # Use an atomic commit to render + ctx = pykms.AtomicReq(self.card) + ctx.add(self.plane, {"FB_ID": drmfb.id, "CRTC_ID": self.crtc.id, + "SRC_W": width << 16, "SRC_H": height << 16, + "CRTC_X": x, "CRTC_Y": y, "CRTC_W": w, "CRTC_H": h}) + ctx.commit_sync() overlay_new_fb = self.overlay_new_fb if overlay_new_fb != self.overlay_fb: From 0bdef3f6691809e1312cb62edc314a90616dd6ec Mon Sep 17 00:00:00 2001 From: jarvis Date: Wed, 2 Aug 2023 23:32:07 -0400 Subject: [PATCH 2/3] Enable atomic rendering for overlays Signed-off-by: Peyton Howe --- picamera2/previews/drm_preview.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/picamera2/previews/drm_preview.py b/picamera2/previews/drm_preview.py index 74419e28..2056bf38 100644 --- a/picamera2/previews/drm_preview.py +++ b/picamera2/previews/drm_preview.py @@ -96,7 +96,6 @@ def set_overlay(self, overlay): raise RuntimeError("Preview must be configured before setting an overlay") if self.picam2.camera_config['buffer_count'] < 2: raise RuntimeError("Need at least buffer_count=2 to set overlay") - if overlay is None: self.overlay_new_fb = None else: @@ -112,6 +111,9 @@ def set_overlay(self, overlay): self.render_drm(self.picam2, None) def render_drm(self, picam2, completed_request): + # Use an atomic commit to render + ctx = pykms.AtomicReq(self.card) + if completed_request is not None: self.display_stream_name = completed_request.config['display'] stream = completed_request.stream_map[self.display_stream_name] @@ -159,7 +161,6 @@ def render_drm(self, picam2, completed_request): self.overlay_plane.set_prop("pixel blend mode", 1) except RuntimeError: pass - if completed_request is not None: fb = completed_request.request.buffers[stream] @@ -191,23 +192,23 @@ def render_drm(self, picam2, completed_request): else: drmfb = pykms.DmabufFramebuffer(self.card, width, height, fmt, [fd], [stride], [0]) self.drmfbs[fb] = drmfb - drmfb = self.drmfbs[fb] - # self.crtc.set_plane(self.plane, drmfb, x, y, w, h, 0, 0, width, height) - # Use an atomic commit to render - ctx = pykms.AtomicReq(self.card) ctx.add(self.plane, {"FB_ID": drmfb.id, "CRTC_ID": self.crtc.id, "SRC_W": width << 16, "SRC_H": height << 16, "CRTC_X": x, "CRTC_Y": y, "CRTC_W": w, "CRTC_H": h}) - ctx.commit_sync() + # Render an overlay if present overlay_new_fb = self.overlay_new_fb if overlay_new_fb != self.overlay_fb: overlay_old_fb = self.overlay_fb # Must hang on to this momentarily to avoid a "wink" self.overlay_fb = overlay_new_fb if self.overlay_fb is not None: width, height = self.overlay_fb.width, self.overlay_fb.height - self.crtc.set_plane(self.overlay_plane, self.overlay_fb, x, y, w, h, 0, 0, width, height) + ctx.add(self.overlay_plane, {"FB_ID": self.overlay_fb.id, "CRTC_ID": self.crtc.id, + "SRC_W": width << 16, "SRC_H": height << 16, + "CRTC_X": x, "CRTC_Y": y, "CRTC_W": w, "CRTC_H": h}) + + ctx.commit_sync() overlay_old_fb = None # noqa The new one has been sent so it's safe to let this go now old_drmfbs = None # noqa Can chuck these away now too From deb4a11ae534b29bff8f0da78f7645c27b0dd5f0 Mon Sep 17 00:00:00 2001 From: jarvis Date: Thu, 3 Aug 2023 00:28:33 -0400 Subject: [PATCH 3/3] Ensure that the overlay and camera frame are drawn in the same atomic commit If the overlay and camera frame are in different atomic commits, then the overlay tends to update at a faster refresh rate, causing the camera feed to 'lag' behind. However, at lower camera framerates, the camera feed renders at the desired framerate, while the overlay updates faster. To remedy the conflicting refresh rates, make sure to only render the overlay with an accompanying camera frame. Signed-off-by: Peyton Howe --- picamera2/previews/drm_preview.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/picamera2/previews/drm_preview.py b/picamera2/previews/drm_preview.py index 2056bf38..a1e8fb53 100644 --- a/picamera2/previews/drm_preview.py +++ b/picamera2/previews/drm_preview.py @@ -106,9 +106,9 @@ def set_overlay(self, overlay): mm.write(np.ascontiguousarray(overlay).data) self.overlay_new_fb = new_fb - if self.picam2.display_stream_name is not None: - with self.lock: - self.render_drm(self.picam2, None) + # if self.picam2.display_stream_name is not None: + # with self.lock: + # self.render_drm(self.picam2, None) def render_drm(self, picam2, completed_request): # Use an atomic commit to render