Update to latest pybind11
authorTomi Valkeinen <tomi.valkeinen@ti.com>
Fri, 24 Nov 2017 07:50:42 +0000 (09:50 +0200)
committerTomi Valkeinen <tomi.valkeinen@ti.com>
Fri, 24 Nov 2017 08:05:01 +0000 (10:05 +0200)
Update to latest pybind11 HEAD. We can't use the latest tag (v2.2.0) as
it has a regression.

There were two problems when updating:

1) Difficulty in managing DrmObject derived classes

Most of the DrmObjects are owned by Card, and can't be allocated or
freed, but a few of them are allocated and freed by the user. For the
former, we need to use unique_ptr with py::nodelete, but that prevents
the latter from working.

The solution was to not tell the python that the latter classes derive
from DrmObject.

This seems to be missing feature in pybind11, but I think we can live
with it.

2) DrmObjects in STL containers

vector<T> where T is a DrmObject derived class doesn't work. We need to
have a manual wrapper to return vector<unique_ptr<T, py::nodelete>>
instead.

This also seems to be a pybind11 missing feature.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
ext/pybind11
py/pykms/pykms.cpp
py/pykms/pykmsbase.cpp
py/pykms/pykmsomap.cpp
py/pykms/pyvid.cpp

index e70b2abb6dee27a2889b01f245a2a28e6fcd4b01..086d53e8c66a84d0ec723d5435918c76edd878e8 160000 (submodule)
@@ -1 +1 @@
-Subproject commit e70b2abb6dee27a2889b01f245a2a28e6fcd4b01
+Subproject commit 086d53e8c66a84d0ec723d5435918c76edd878e8
index 1e54c9bb4501d4732d37092bcf4f12fc2448d62d..fec84170f9eee02cd8f51f5b4aa9feb6aab5aabd 100644 (file)
@@ -15,9 +15,7 @@ void init_pyvid(py::module &m);
 void init_pykmsomap(py::module &m);
 #endif
 
-PYBIND11_PLUGIN(pykms) {
-       py::module m("pykms", "kms bindings");
-
+PYBIND11_MODULE(pykms, m) {
        init_pykmsbase(m);
 
        init_pykmstest(m);
@@ -27,5 +25,4 @@ PYBIND11_PLUGIN(pykms) {
 #if HAS_LIBDRM_OMAP
        init_pykmsomap(m);
 #endif
-       return m.ptr();
 }
index fe4bc463ab699e899c05f1a49b8ff328b5ced4e9..aae5ecec6ea32e31f5361ec6a52874064ab5c7ee 100644 (file)
@@ -12,22 +12,36 @@ void init_pykmsbase(py::module &m)
        py::class_<Card>(m, "Card")
                        .def(py::init<>())
                        .def_property_readonly("fd", &Card::fd)
-                       .def("get_first_connected_connector", &Card::get_first_connected_connector)
-                       .def_property_readonly("connectors", &Card::get_connectors)
-                       .def_property_readonly("crtcs", &Card::get_crtcs)
-                       .def_property_readonly("encoders", &Card::get_encoders)
-                       .def_property_readonly("planes", &Card::get_planes)
+                       .def_property_readonly("get_first_connected_connector", &Card::get_first_connected_connector)
+
+                       // XXX pybind11 can't handle vector<T*> where T is non-copyable, and complains:
+                       // RuntimeError: return_value_policy = move, but the object is neither movable nor copyable!
+                       // So we do this manually.
+                       .def_property_readonly("connectors", [](Card* self) {
+                               vector<unique_ptr<Connector, py::nodelete>> v;
+                               for (Connector* p : self->get_connectors())
+                                       v.push_back(unique_ptr<Connector, py::nodelete>(p));
+                               return v;
+                       })
+
+                       .def_property_readonly("planes", [](Card* self) {
+                               vector<unique_ptr<Plane, py::nodelete>> v;
+                               for (Plane* p : self->get_planes())
+                                       v.push_back(unique_ptr<Plane, py::nodelete>(p));
+                               return v;
+                       })
+
                        .def_property_readonly("has_atomic", &Card::has_atomic)
                        .def("get_prop", (Property* (Card::*)(uint32_t) const)&Card::get_prop)
                        ;
 
-       py::class_<DrmObject, DrmObject*>(m, "DrmObject")
+       py::class_<DrmObject, unique_ptr<DrmObject, py::nodelete>>(m, "DrmObject")
                        .def_property_readonly("id", &DrmObject::id)
                        .def_property_readonly("idx", &DrmObject::idx)
                        .def_property_readonly("card", &DrmObject::card)
                        ;
 
-       py::class_<DrmPropObject, DrmPropObject*>(m, "DrmPropObject", py::base<DrmObject>())
+       py::class_<DrmPropObject, DrmObject, unique_ptr<DrmPropObject, py::nodelete>>(m, "DrmPropObject")
                        .def("refresh_props", &DrmPropObject::refresh_props)
                        .def_property_readonly("prop_map", &DrmPropObject::get_prop_map)
                        .def("get_prop_value", (uint64_t (DrmPropObject::*)(const string&) const)&DrmPropObject::get_prop_value)
@@ -36,7 +50,7 @@ void init_pykmsbase(py::module &m)
                        .def("get_prop", &DrmPropObject::get_prop)
                        ;
 
-       py::class_<Connector, Connector*>(m, "Connector",  py::base<DrmPropObject>())
+       py::class_<Connector, DrmPropObject, unique_ptr<Connector, py::nodelete>>(m, "Connector")
                        .def_property_readonly("fullname", &Connector::fullname)
                        .def("get_default_mode", &Connector::get_default_mode)
                        .def("get_current_crtc", &Connector::get_current_crtc)
@@ -49,7 +63,7 @@ void init_pykmsbase(py::module &m)
                        .def("refresh", &Connector::refresh)
                        ;
 
-       py::class_<Crtc, Crtc*>(m, "Crtc",  py::base<DrmPropObject>())
+       py::class_<Crtc, DrmPropObject, unique_ptr<Crtc, py::nodelete>>(m, "Crtc")
                        .def("set_mode", (int (Crtc::*)(Connector*, const Videomode&))&Crtc::set_mode)
                        .def("set_mode", (int (Crtc::*)(Connector*, Framebuffer&, const Videomode&))&Crtc::set_mode)
                        .def("disable_mode", &Crtc::disable_mode)
@@ -67,11 +81,11 @@ void init_pykmsbase(py::module &m)
                        .def("refresh", &Crtc::refresh)
                        ;
 
-       py::class_<Encoder, Encoder*>(m, "Encoder",  py::base<DrmPropObject>())
+       py::class_<Encoder, DrmPropObject, unique_ptr<Encoder, py::nodelete>>(m, "Encoder")
                        .def("refresh", &Encoder::refresh)
                        ;
 
-       py::class_<Plane, Plane*>(m, "Plane",  py::base<DrmPropObject>())
+       py::class_<Plane, DrmPropObject, unique_ptr<Plane, py::nodelete>>(m, "Plane")
                        .def("supports_crtc", &Plane::supports_crtc)
                        .def_property_readonly("formats", &Plane::get_formats)
                        .def_property_readonly("plane_type", &Plane::plane_type)
@@ -84,12 +98,12 @@ void init_pykmsbase(py::module &m)
                        .value("Cursor", PlaneType::Cursor)
                        ;
 
-       py::class_<Property, Property*>(m, "Property",  py::base<DrmObject>())
+       py::class_<Property, DrmObject, unique_ptr<Property, py::nodelete>>(m, "Property")
                        .def_property_readonly("name", &Property::name)
                        .def_property_readonly("enums", &Property::get_enums)
                        ;
 
-       py::class_<Blob>(m, "Blob", py::base<DrmObject>())
+       py::class_<Blob>(m, "Blob")
                        .def("__init__", [](Blob& instance, Card& card, py::buffer buf) {
                                py::buffer_info info = buf.request();
                                if (info.ndim != 1)
@@ -98,17 +112,30 @@ void init_pykmsbase(py::module &m)
                                new (&instance) Blob(card, info.ptr, info.size * info.itemsize);
                        })
                        .def_property_readonly("data", &Blob::data)
-                       ;
 
-       py::class_<Framebuffer>(m, "Framebuffer", py::base<DrmObject>())
+                       // XXX pybind11 doesn't support a base object (DrmObject) with custom holder-type,
+                       // and a subclass with standard holder-type.
+                       // So we just copy the DrmObject members here.
+                       // Note that this means that python thinks we don't derive from DrmObject
+                       .def_property_readonly("id", &DrmObject::id)
+                       .def_property_readonly("idx", &DrmObject::idx)
+                       .def_property_readonly("card", &DrmObject::card)
                        ;
 
-       py::class_<Framebuffer>(m, "Framebuffer", py::base<Framebuffer>())
+       py::class_<Framebuffer>(m, "Framebuffer")
                        .def_property_readonly("width", &Framebuffer::width)
                        .def_property_readonly("height", &Framebuffer::height)
+
+                       // XXX pybind11 doesn't support a base object (DrmObject) with custom holder-type,
+                       // and a subclass with standard holder-type.
+                       // So we just copy the DrmObject members here.
+                       // Note that this means that python thinks we don't derive from DrmObject
+                       .def_property_readonly("id", &DrmObject::id)
+                       .def_property_readonly("idx", &DrmObject::idx)
+                       .def_property_readonly("card", &DrmObject::card)
                        ;
 
-       py::class_<DumbFramebuffer>(m, "DumbFramebuffer", py::base<Framebuffer>())
+       py::class_<DumbFramebuffer, Framebuffer>(m, "DumbFramebuffer")
                        .def(py::init<Card&, uint32_t, uint32_t, const string&>(),
                             py::keep_alive<1, 2>())    // Keep Card alive until this is destructed
                        .def(py::init<Card&, uint32_t, uint32_t, PixelFormat>(),
@@ -120,7 +147,7 @@ void init_pykmsbase(py::module &m)
                        .def("offset", &DumbFramebuffer::offset)
                        ;
 
-       py::class_<ExtFramebuffer>(m, "ExtFramebuffer", py::base<Framebuffer>())
+       py::class_<ExtFramebuffer, Framebuffer>(m, "ExtFramebuffer")
                        .def(py::init<Card&, uint32_t, uint32_t, PixelFormat, vector<int>, vector<uint32_t>, vector<uint32_t>>(),
                             py::keep_alive<1, 2>())    // Keep Card alive until this is destructed
                        ;
index 2662a18a6f29c33cc16b03ccf803761a76d90be8..4fc7084e5ae2f6a05c9e0cb230fd89849e61ed85 100644 (file)
@@ -10,11 +10,11 @@ using namespace std;
 
 void init_pykmsomap(py::module &m)
 {
-       py::class_<OmapCard>(m, "OmapCard", py::base<Card>())
+       py::class_<OmapCard, Card>(m, "OmapCard")
                        .def(py::init<>())
                        ;
 
-       py::class_<OmapFramebuffer> omapfb(m, "OmapFramebuffer", py::base<Framebuffer>());
+       py::class_<OmapFramebuffer, Framebuffer> omapfb(m, "OmapFramebuffer");
 
        // XXX we should use py::arithmetic() here to support or and and operators, but it's not supported in the pybind11 we use
        py::enum_<OmapFramebuffer::Flags>(omapfb, "Flags")
index 01177d5dd014c736985962c9a2ced77672c487b0..6a6080e4b2b7bb0be76ba1373d13a705a1e289be 100644 (file)
@@ -11,7 +11,7 @@ using namespace std;
 
 void init_pyvid(py::module &m)
 {
-       py::class_<VideoDevice, VideoDevice*>(m, "VideoDevice")
+       py::class_<VideoDevice>(m, "VideoDevice")
                        .def(py::init<const string&>())
                        .def_property_readonly("fd", &VideoDevice::fd)
                        .def_property_readonly("has_capture", &VideoDevice::has_capture)
@@ -24,7 +24,7 @@ void init_pyvid(py::module &m)
                        .def("get_capture_devices", &VideoDevice::get_capture_devices)
                        ;
 
-       py::class_<VideoStreamer, VideoStreamer*>(m, "VideoStreamer")
+       py::class_<VideoStreamer>(m, "VideoStreamer")
                        .def_property_readonly("fd", &VideoStreamer::fd)
                        .def_property_readonly("ports", &VideoStreamer::get_ports)
                        .def("set_port", &VideoStreamer::set_port)