New event handling
authorTomi Valkeinen <tomi.valkeinen@ti.com>
Wed, 8 Mar 2017 10:11:11 +0000 (12:11 +0200)
committerTomi Valkeinen <tomi.valkeinen@ti.com>
Wed, 8 Mar 2017 10:56:29 +0000 (12:56 +0200)
The current event handling relies on the PageFlipHandlerBase class which
has to be implemented on the python side.

This patch implements a more versatile event handling, where any python
object can be passed as data to the commit or page flip, and it's up to
the python implementation to decide what to do with that data when
receiving the event.

Note that when doing the commit or page_flip, the ref count of the
given python object is incremented to keep it alive. The ref count is
decremented when reading the events with the new helper method
card.read_events(). This helper _has_ to be used to ensure the objects
get released properly.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
py/pykms/__init__.py
py/pykms/pykms.cpp
py/pykms/pykmsbase.cpp
py/tests/db.py

index d4cdc43d2f4ddc7cae2a2193b8a6877c26a8d0d7..41c12195d7f52621a3adcf9b01b20e742fb29cea 100644 (file)
@@ -1,4 +1,7 @@
 from .pykms import *
+from enum import Enum
+import os
+import struct
 
 #
 # Common RGB colours
@@ -58,3 +61,65 @@ def __card_disable_planes(self):
         print("disabling planes failed")
 
 Card.disable_planes = __card_disable_planes
+
+class DrmEventType(Enum):
+    VBLANK = 0x01
+    FLIP_COMPLETE = 0x02
+
+# struct drm_event {
+#   __u32 type;
+#   __u32 length;
+#};
+#
+
+_drm_ev = struct.Struct("II")
+
+#struct drm_event_vblank {
+#   struct drm_event base;
+#   __u64 user_data;
+#   __u32 tv_sec;
+#   __u32 tv_usec;
+#   __u32 sequence;
+#   __u32 reserved;
+#};
+
+_drm_ev_vbl = struct.Struct("QIIII") # Note: doesn't contain drm_event
+
+class DrmEvent:
+    def __init__(self, type, seq, time, data):
+        self.type = type
+        self.seq = seq
+        self.time = time
+        self.data = data
+
+# Return DrmEvents. Note: blocks if there's nothing to read
+def __card_read_events(self):
+    buf = os.read(self.fd, _drm_ev_vbl.size * 20)
+
+    if len(buf) == 0:
+        return
+
+    if len(buf) < _drm_ev.size:
+        raise RuntimeError("Partial DRM event")
+
+    idx = 0
+
+    while idx < len(buf):
+        ev_tuple = _drm_ev.unpack_from(buf, idx)
+
+        type = DrmEventType(ev_tuple[0])
+
+        if type != DrmEventType.VBLANK and type != DrmEventType.FLIP_COMPLETE:
+            raise RuntimeError("Illegal DRM event type")
+
+        vbl_tuple = _drm_ev_vbl.unpack_from(buf, idx + _drm_ev.size)
+
+        seq = vbl_tuple[3]
+        time = vbl_tuple[1] + vbl_tuple[2] / 1000000.0;
+        udata = pykms.__ob_unpack_helper(vbl_tuple[0])
+
+        yield DrmEvent(type, seq, time, udata)
+
+        idx += ev_tuple[1]
+
+Card.read_events = __card_read_events
index 219903926521ca51a64877ac7cf2a92aab3b1ff4..7752f19142815c402436f38f0f75b9c72db90c1f 100644 (file)
@@ -15,32 +15,15 @@ void init_pyvid(py::module &m);
 void init_pykmsomap(py::module &m);
 #endif
 
-class PyPageFlipHandlerBase : PageFlipHandlerBase
-{
-public:
-       using PageFlipHandlerBase::PageFlipHandlerBase;
-
-       virtual void handle_page_flip(uint32_t frame, double time)
-       {
-               PYBIND11_OVERLOAD_PURE(
-                                       void,                /* Return type */
-                                       PageFlipHandlerBase, /* Parent class */
-                                       handle_page_flip,    /* Name of function */
-                                       frame, time
-                                       );
-       }
-};
-
 PYBIND11_PLUGIN(pykms) {
        py::module m("pykms", "kms bindings");
 
        init_pykmsbase(m);
 
-       py::class_<PyPageFlipHandlerBase>(m, "PageFlipHandlerBase")
-                       .alias<PageFlipHandlerBase>()
-                       .def(py::init<>())
-                       .def("handle_page_flip", &PageFlipHandlerBase::handle_page_flip)
-                       ;
+       m.def("__ob_unpack_helper", [](uint64_t v) {
+               // AtomicReq::commit or Crtc::page_flip added a ref, so we can use borrowed = false
+               return py::object((PyObject*)v, false);
+       });
 
        init_pykmstest(m);
 
index 0d5bb86534dfff98e6a18f5e74cfad88a605e758..1cc91d8d3651617ec1e0e415167c15e951e44d47 100644 (file)
@@ -18,7 +18,6 @@ void init_pykmsbase(py::module &m)
                        .def_property_readonly("encoders", &Card::get_encoders)
                        .def_property_readonly("planes", &Card::get_planes)
                        .def_property_readonly("has_atomic", &Card::has_atomic)
-                       .def("call_page_flip_handlers", &Card::call_page_flip_handlers)
                        .def("get_prop", (Property* (Card::*)(uint32_t) const)&Card::get_prop)
                        ;
 
@@ -49,7 +48,14 @@ void init_pykmsbase(py::module &m)
 
        py::class_<Crtc, Crtc*>(m, "Crtc",  py::base<DrmPropObject>())
                        .def("set_mode", &Crtc::set_mode)
-                       .def("page_flip", &Crtc::page_flip)
+                       .def("page_flip",
+                            [](Crtc* self, Framebuffer& fb, py::object ob)
+                               {
+                                       // This adds a ref to the object, and must be unpacked with __ob_unpack_helper()
+                                       PyObject* pob = ob.ptr();
+                                       Py_XINCREF(pob);
+                                       self->page_flip(fb, pob);
+                               })
                        .def("set_plane", &Crtc::set_plane)
                        .def_property_readonly("possible_planes", &Crtc::get_possible_planes)
                        .def_property_readonly("primary_plane", &Crtc::get_primary_plane)
@@ -167,7 +173,14 @@ void init_pykmsbase(py::module &m)
                        .def("add", (void (AtomicReq::*)(DrmPropObject*, const string&, uint64_t)) &AtomicReq::add)
                        .def("add", (void (AtomicReq::*)(DrmPropObject*, const map<string, uint64_t>&)) &AtomicReq::add)
                        .def("test", &AtomicReq::test, py::arg("allow_modeset") = false)
-                       .def("commit", &AtomicReq::commit, py::arg("data"), py::arg("allow_modeset") = false)
+                       .def("commit",
+                            [](AtomicReq* self, py::object ob, bool allow)
+                               {
+                                       // This adds a ref to the object, and must be unpacked with __ob_unpack_helper()
+                                       PyObject* pob = ob.ptr();
+                                       Py_XINCREF(pob);
+                                       self->commit(pob, allow);
+                               }, py::arg("data"), py::arg("allow_modeset") = false)
                        .def("commit_sync", &AtomicReq::commit_sync, py::arg("allow_modeset") = false)
                        ;
 }
index eb31669ff5b6b3653de70736b93f89f36cae9584..d51820c5970861fdd4a4d926b6dbbb0990ff5946 100755 (executable)
@@ -7,7 +7,7 @@ import selectors
 bar_width = 20
 bar_speed = 8
 
-class FlipHandler(pykms.PageFlipHandlerBase):
+class FlipHandler():
     def __init__(self):
         super().__init__()
         self.bar_xpos = 0
@@ -75,7 +75,11 @@ fliphandler.handle_page_flip(0, 0)
 
 def readdrm(fileobj, mask):
     #print("EVENT");
-    card.call_page_flip_handlers()
+    #card.call_page_flip_handlers()
+    for ev in card.read_events():
+        if ev.type == pykms.DrmEventType.FLIP_COMPLETE:
+            ev.data.handle_page_flip(ev.seq, ev.time)
+
 
 def readkey(fileobj, mask):
     #print("KEY EVENT");