Skip to content

Commit 7b0a3e0

Browse files
davidplowmanchrisruk
authored andcommitted
Implement overlays for the DRM/KMS preview
Signed-off-by: David Plowman <[email protected]>
1 parent 03b227a commit 7b0a3e0

File tree

1 file changed

+42
-3
lines changed

1 file changed

+42
-3
lines changed

picamera2/previews/drm_preview.py

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import picamera2.picamera2
22
import pykms
3+
import mmap
4+
import numpy as np
35
from picamera2.previews.null_preview import *
46

7+
dd = None
58

69
class DrmPreview(NullPreview):
710
FMT_MAP = {
@@ -36,6 +39,20 @@ def init_drm(self, x, y, width, height):
3639
self.drmfbs = {}
3740
self.current = None
3841
self.window = (x, y, width, height)
42+
self.overlay_plane = None
43+
self.overlay_fb = None
44+
self.overlay_new_fb = None
45+
46+
def set_overlay(self, overlay):
47+
if overlay is None:
48+
self.overlay_new_fb = None
49+
else:
50+
h, w, channels = overlay.shape
51+
# Should I be recycling these instead of making new ones all the time?
52+
new_fb = pykms.DumbFramebuffer(self.card, w, h, "AB24")
53+
with mmap.mmap(new_fb.fd(0), w * h * 4, mmap.MAP_SHARED, mmap.PROT_WRITE) as mm:
54+
mm.write(np.ascontiguousarray(overlay).data)
55+
self.overlay_new_fb = new_fb
3956

4057
def render_drm(self, picam2, completed_request):
4158
if picam2.display_stream_name is None:
@@ -55,9 +72,14 @@ def render_drm(self, picam2, completed_request):
5572
fmt = self.FMT_MAP[cfg.pixelFormat]
5673
if self.plane is None:
5774
self.plane = self.resman.reserve_overlay_plane(self.crtc, fmt)
58-
if picam2.verbose_console:
59-
print("Got plane", self.plane, "for format", fmt)
60-
assert(self.plane)
75+
if self.plane is None:
76+
raise RuntimeError("Failed to reserve DRM plane")
77+
# The second plane we ask for will go on top of the first.
78+
self.overlay_plane = self.resman.reserve_overlay_plane(self.crtc, pykms.PixelFormat.ABGR8888)
79+
if self.overlay_plane is None:
80+
raise RuntimeError("Failed to reserve DRM overlay plane")
81+
# Want "coverage" mode, not pre-multiplied alpha.
82+
self.overlay_plane.set_prop("pixel blend mode", 1)
6183
fd = fb.fd(0)
6284
stride = cfg.stride
6385
if cfg.pixelFormat in ("YUV420", "YVU420"):
@@ -77,6 +99,21 @@ def render_drm(self, picam2, completed_request):
7799
drmfb = self.drmfbs[fb]
78100
x, y, w, h = self.window
79101
self.crtc.set_plane(self.plane, drmfb, x, y, w, h, 0, 0, width, height)
102+
# An "atomic commit" would probably be better, but I can't get this to work...
103+
# ctx = pykms.AtomicReq(self.card)
104+
# ctx.add(self.plane, {"FB_ID": drmfb.id, "CRTC_ID": self.crtc.id,
105+
# "SRC_W": width << 16, "SRC_H": height << 16,
106+
# "CRTC_X": x, "CRTC_Y": y, "CRTC_W": w, "CRTC_H": h})
107+
# ctx.commit()
108+
109+
overlay_new_fb = self.overlay_new_fb
110+
if overlay_new_fb != self.overlay_fb:
111+
overlay_old_fb = self.overlay_fb # Must hang on to this momentarily to avoid a "wink"
112+
self.overlay_fb = overlay_new_fb
113+
if self.overlay_fb is not None:
114+
width, height = self.overlay_fb.width, self.overlay_fb.height
115+
self.crtc.set_plane(self.overlay_plane, self.overlay_fb, x, y, w, h, 0, 0, width, height)
116+
overlay_old_fb = None # The new one has been sent so it's safe to let this go now
80117

81118
if self.current:
82119
self.current.release()
@@ -86,6 +123,8 @@ def stop(self):
86123
super().stop()
87124
# Seem to need some of this in order to be able to create another DrmPreview.
88125
self.drmfbs = {}
126+
self.overlay_new_fb = None
127+
self.overlay_fb = None
89128
self.crtc = None
90129
self.resman = None
91130
self.card = None

0 commit comments

Comments
 (0)