diff --git a/.gitignore b/.gitignore index cd4a97f0..0aa9d94f 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,8 @@ tmp/ checkpatch.pl const_structs.checkpatch spelling.txt + +__pycache__/ +evdienv/ +.cache/ +compile_commands.json diff --git a/pyevdi/Buffer.cpp b/pyevdi/Buffer.cpp index 645ea68c..9876b175 100644 --- a/pyevdi/Buffer.cpp +++ b/pyevdi/Buffer.cpp @@ -1,9 +1,10 @@ // Copyright (c) 2022 DisplayLink (UK) Ltd. -#include "Buffer.h" -#include "../library/evdi_lib.h" #include #include +#include "../library/evdi_lib.h" +#include "Buffer.h" + int Buffer::numerator = 0; Buffer::Buffer(evdi_mode mode, evdi_handle evdiHandle) @@ -25,8 +26,13 @@ Buffer::Buffer(evdi_mode mode, evdi_handle evdiHandle) buffer.rect_count = 16; buffer.rects = reinterpret_cast( calloc(buffer.rect_count, sizeof(struct evdi_rect))); - buffer.buffer = - calloc(mode.width * mode.width, mode.bits_per_pixel / 8); + rects_span = std::span(buffer.rects, buffer.rect_count); + bytes_per_pixel = mode.bits_per_pixel / 8; + buffer_size = mode.width * mode.height * bytes_per_pixel; + buffer.buffer = calloc(1, buffer_size); + buffer_span = + std::span(reinterpret_cast(buffer.buffer), + buffer_size / sizeof(uint32_t)); evdi_register_buffer(evdiHandle, buffer); } diff --git a/pyevdi/Buffer.h b/pyevdi/Buffer.h index 58f2bb70..7927b198 100644 --- a/pyevdi/Buffer.h +++ b/pyevdi/Buffer.h @@ -3,7 +3,10 @@ #define BUFFER_H #include "../library/evdi_lib.h" +#include #include +#include +#include class Buffer : public std::enable_shared_from_this { static int numerator; @@ -11,6 +14,10 @@ class Buffer : public std::enable_shared_from_this { public: evdi_buffer buffer; + size_t buffer_size; + std::span rects_span; + std::span buffer_span; + size_t bytes_per_pixel; Buffer(evdi_mode mode, evdi_handle evdiHandle); ~Buffer(); }; diff --git a/pyevdi/Card.cpp b/pyevdi/Card.cpp index f6532e08..06c121f9 100644 --- a/pyevdi/Card.cpp +++ b/pyevdi/Card.cpp @@ -1,6 +1,7 @@ // Copyright (c) 2022 DisplayLink (UK) Ltd. +#include + #include "../library/evdi_lib.h" -#include #include "Card.h" #include "Buffer.h" @@ -24,8 +25,8 @@ void card_C_mode_handler(struct evdi_mode mode, void *user_data) card->setMode(mode); card->makeBuffers(2); - if (card->m_modeHandler != nullptr) { - card->m_modeHandler(mode); + if (!card->mode_handler.is_none()) { + card->mode_handler(mode); } card->request_update(); @@ -53,23 +54,19 @@ void Card::clearBuffers() void dpms_handler(int dpms_mode, void * /*user_data*/) { py::module logging = py::module::import("logging"); - logging.attr("info")("Got dpms signal." + std::to_string(dpms_mode)); + logging.attr("info")(std::format("Got dpms signal: \"{}\"", dpms_mode)); } Card::Card(int device) : evdiHandle(evdi_open(device)) { if (evdiHandle == nullptr) { - throw py::value_error("Card /dev/dri/card" + - std::to_string(device) + - "does not exists!"); + throw py::value_error(std::format( + "Failed to open card \"/dev/dri/card{}\"", device)); } memset(&eventContext, 0, sizeof(eventContext)); - m_modeHandler = nullptr; - acquire_framebuffer_cb = nullptr; - eventContext.mode_changed_handler = &card_C_mode_handler; eventContext.update_ready_handler = &default_update_ready_handler; eventContext.dpms_handler = dpms_handler; @@ -161,8 +158,8 @@ void Card::grab_pixels() evdi_grab_pixels(evdiHandle, buffer_requested->buffer.rects, &buffer_requested->buffer.rect_count); - if (acquire_framebuffer_cb) - acquire_framebuffer_cb(std::move(buffer_requested)); + if (acquire_framebuffer_handler) + acquire_framebuffer_handler(std::move(buffer_requested)); buffer_requested = nullptr; request_update(); diff --git a/pyevdi/Card.h b/pyevdi/Card.h index 1e62fd56..8a908ea0 100644 --- a/pyevdi/Card.h +++ b/pyevdi/Card.h @@ -2,10 +2,16 @@ #ifndef CARD_H #define CARD_H -#include "Buffer.h" +#include +#include +#include #include #include +#include "Buffer.h" + +namespace py = pybind11; + class Card { evdi_handle evdiHandle; evdi_event_context eventContext; @@ -25,9 +31,11 @@ class Card { friend void card_C_mode_handler(struct evdi_mode mode, void *user_data); public: - std::function m_modeHandler; - std::function buffer)> - acquire_framebuffer_cb; + /// used py::function to allow lambdas to work + /// void(struct evdi_mode) + py::function mode_handler; + /// void(std::shared_ptr buffer) + py::function acquire_framebuffer_handler; explicit Card(int device); ~Card(); diff --git a/pyevdi/Makefile b/pyevdi/Makefile index 08a7e20a..8a7c94e5 100644 --- a/pyevdi/Makefile +++ b/pyevdi/Makefile @@ -11,7 +11,8 @@ LIBABI := 1 INCL_DIRS := -I../library $$(python3 -m pybind11 --includes) -CXXFLAGS := $(INCL_DIRS) -std=c++11 -fPIC $(CXXFLAGS) +# -fvisibility=hidden https://pybind11.readthedocs.io/en/stable/faq.html#someclass-declared-with-greater-visibility-than-the-type-of-its-field-someclass-member-wattributes +CXXFLAGS := $(INCL_DIRS) -std=c++20 -fPIC -fvisibility=hidden $(CXXFLAGS) LDFLAGS := -L../library -Wl,--no-undefined $$(python3-config --ldflags --embed) -shared @@ -39,7 +40,7 @@ tests: LD_LIBRARY_PATH=../library python3 -m pytest test/ -LIBDIR ?= /usr/lib/python$$(python3 -c "import sys; print (sys.version[:3])")/lib-dynload +LIBDIR ?= $$(python3 -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") install: diff --git a/pyevdi/PyEvdi.cpp b/pyevdi/PyEvdi.cpp index f30cc2a1..cfd26b5a 100644 --- a/pyevdi/PyEvdi.cpp +++ b/pyevdi/PyEvdi.cpp @@ -1,12 +1,17 @@ // Copyright (c) 2022 DisplayLink (UK) Ltd. -#include "../library/evdi_lib.h" +#include "pybind11/pytypes.h" +#include #include #include -#include "Card.h" -#include -#include #include #include +#include +#include +#include +#include + +#include "../library/evdi_lib.h" +#include "Card.h" namespace py = pybind11; @@ -33,7 +38,7 @@ void log_function(void * /*user_data*/, const char *format, ...) PYBIND11_MODULE(PyEvdi, m) { - m.doc() = "python bindings for evdi library"; + m.doc() = "Python bindings for evdi library"; evdi_logging el; el.function = &log_function; @@ -70,36 +75,20 @@ PYBIND11_MODULE(PyEvdi, m) .def_readwrite("y1", &evdi_rect::y1) .def_readwrite("y2", &evdi_rect::y2); - py::class_ >(m, "Buffer") - .def_property_readonly( - "id", [](Buffer &self) { return self.buffer.id; }) - .def_property_readonly("bytes", - [](Buffer &self) { - return self.buffer.buffer; - }) - .def_property_readonly( - "width", [](Buffer &self) { return self.buffer.width; }) - .def_property_readonly("height", - [](Buffer &self) { - return self.buffer.height; - }) - .def_property_readonly("stride", - [](Buffer &self) { - return self.buffer.stride; - }) - .def_property_readonly( - "rects", - [](Buffer &self) { - std::vector rects; - for (int i = 0; i < self.buffer.rect_count; - i++) { - rects.push_back(self.buffer.rects[i]); - } - return rects; - }) - .def_property_readonly("rect_count", [](Buffer &self) { - return self.buffer.rect_count; - }); + py::class_>(m, "Buffer") + .def_property_readonly("id", [](Buffer& self) { return self.buffer.id; }) + .def_property_readonly("bytes", [](Buffer& self) { return self.buffer.buffer; }) + .def_property_readonly("width", [](Buffer& self) { return self.buffer.width; }) + .def_property_readonly("height", [](Buffer& self) { return self.buffer.height; }) + .def_property_readonly("stride", [](Buffer& self) { return self.buffer.stride; }) + .def_property_readonly("rects", [](Buffer& self) { + std::vector rects; + for(int i = 0; i < self.buffer.rect_count; i++){ + rects.push_back(self.buffer.rects[i]); + } + return rects; + }) + .def_property_readonly("rect_count", [](Buffer& self) { return self.buffer.rect_count; }); py::class_(m, "Card") .def(py::init()) @@ -108,7 +97,7 @@ PYBIND11_MODULE(PyEvdi, m) .def("connect", &Card::connect) .def("disconnect", &Card::disconnect) .def("handle_events", &Card::handle_events) - .def_readwrite("acquire_framebuffer_cb", - &Card::acquire_framebuffer_cb) - .def_readwrite("mode_changed_handler", &Card::m_modeHandler); + .def_readwrite("acquire_framebuffer_handler", + &Card::acquire_framebuffer_handler) + .def_readwrite("mode_changed_handler", &Card::mode_handler); } diff --git a/pyevdi/README.md b/pyevdi/README.md new file mode 100644 index 00000000..834072b7 --- /dev/null +++ b/pyevdi/README.md @@ -0,0 +1,23 @@ +# Installing PyEvdi + +Create a virtual environment and install the package: + +```bash +python3 -m venv evdienv +source evdienv/bin/activate +pip install pybind11 +make install +``` + +To run tests: +```bash +pip install pytest +pytest test +``` + +# Generate `compile_commands.json` + +```bash +yay -Sy --needed bear +bear -- make +``` \ No newline at end of file diff --git a/pyevdi/4K60HzTest.edid b/pyevdi/sample_edid/4K60HzTest.edid similarity index 100% rename from pyevdi/4K60HzTest.edid rename to pyevdi/sample_edid/4K60HzTest.edid diff --git a/pyevdi/sample_edid/README.md b/pyevdi/sample_edid/README.md new file mode 100644 index 00000000..c052c5e2 --- /dev/null +++ b/pyevdi/sample_edid/README.md @@ -0,0 +1,4 @@ +# How to get an EDID file +``` +cp /sys/class/drm/card0-eDP-1/edid edid.bin +``` \ No newline at end of file diff --git a/pyevdi/test/test_connect.py b/pyevdi/test/test_connect.py index c24f00b5..632e7d77 100644 --- a/pyevdi/test/test_connect.py +++ b/pyevdi/test/test_connect.py @@ -51,7 +51,7 @@ def testHandlingEventsTenTimesWithDefaultHandlers(): card.disconnect() card.close() -def my_acquire_framebuffer_cb(buffer) -> None: +def my_acquire_framebuffer_handler(buffer) -> None: print("received buffer", buffer.id) print("rect_count:", buffer.rect_count, "\nrects:") for i in buffer.rects: @@ -63,7 +63,7 @@ def my_acquire_framebuffer_cb(buffer) -> None: def testHandlingEventsTenTimesWithAquireFramebufferSet(): card = PyEvdi.Card(utilities.get_available_evdi_card()) - card.acquire_framebuffer_cb = my_acquire_framebuffer_cb + card.acquire_framebuffer_handler = my_acquire_framebuffer_handler edid = utilities.get_edid() card.connect(edid, len(edid), utilities._FullHDAreaLimit, utilities._FullHDAreaLimit * utilities._60Hz) diff --git a/pyevdi/test/utilities.py b/pyevdi/test/utilities.py index d22e2f00..2e432fc2 100644 --- a/pyevdi/test/utilities.py +++ b/pyevdi/test/utilities.py @@ -20,6 +20,6 @@ def get_available_evdi_card(): return -1 def get_edid(): - with open("4K60HzTest.edid", mode='rb') as file: + with open("sample_edid/4K60HzTest.edid", mode='rb') as file: ed = file.read() return ed