diff options
-rw-r--r-- | kms++/inc/kms++/omap/omapframebuffer.h | 15 | ||||
-rw-r--r-- | kms++/src/omap/omapframebuffer.cpp | 81 | ||||
-rw-r--r-- | py/pykms/__init__.py | 14 | ||||
-rw-r--r-- | py/pykms/pykmsomap.cpp | 24 | ||||
-rwxr-xr-x | py/tests/cam.py | 12 | ||||
-rwxr-xr-x | py/tests/rottest.py | 171 |
6 files changed, 290 insertions, 27 deletions
diff --git a/kms++/inc/kms++/omap/omapframebuffer.h b/kms++/inc/kms++/omap/omapframebuffer.h index 16d6cf8..d1152b5 100644 --- a/kms++/inc/kms++/omap/omapframebuffer.h +++ b/kms++/inc/kms++/omap/omapframebuffer.h @@ -12,8 +12,17 @@ class OmapCard; class OmapFramebuffer : public MappedFramebuffer { public: - OmapFramebuffer(OmapCard& card, uint32_t width, uint32_t height, const std::string& fourcc); - OmapFramebuffer(OmapCard& card, uint32_t width, uint32_t height, PixelFormat format); + enum Flags + { + None = 0, + Tiled = 1 << 0, + MemContig = 1 << 1, + MemTiler = 1 << 2, + MemPin = 1 << 3, + }; + + OmapFramebuffer(OmapCard& card, uint32_t width, uint32_t height, const std::string& fourcc, Flags flags = Flags::None); + OmapFramebuffer(OmapCard& card, uint32_t width, uint32_t height, PixelFormat format, Flags flags = Flags::None); virtual ~OmapFramebuffer(); uint32_t width() const { return Framebuffer::width(); } @@ -42,7 +51,7 @@ private: uint8_t* map; }; - void Create(); + void Create(Flags buffer_flags); void Destroy(); unsigned m_num_planes; diff --git a/kms++/src/omap/omapframebuffer.cpp b/kms++/src/omap/omapframebuffer.cpp index e1e2234..b27ca22 100644 --- a/kms++/src/omap/omapframebuffer.cpp +++ b/kms++/src/omap/omapframebuffer.cpp @@ -17,20 +17,24 @@ extern "C" { #include <omap_drmif.h> } +#define __round_mask(x, y) ((__typeof__(x))((y)-1)) +#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) +#define PAGE_SIZE 4096 + using namespace std; namespace kms { -OmapFramebuffer::OmapFramebuffer(OmapCard& card, uint32_t width, uint32_t height, const string& fourcc) - : OmapFramebuffer(card, width, height, FourCCToPixelFormat(fourcc)) +OmapFramebuffer::OmapFramebuffer(OmapCard& card, uint32_t width, uint32_t height, const string& fourcc, Flags flags) + : OmapFramebuffer(card, width, height, FourCCToPixelFormat(fourcc), flags) { } -OmapFramebuffer::OmapFramebuffer(OmapCard& card, uint32_t width, uint32_t height, PixelFormat format) - : MappedFramebuffer(card, width, height), m_omap_card(card), m_format(format) +OmapFramebuffer::OmapFramebuffer(OmapCard& card, uint32_t width, uint32_t height, PixelFormat format, Flags flags) + :MappedFramebuffer(card, width, height), m_omap_card(card), m_format(format) { - Create(); + Create(flags); } OmapFramebuffer::~OmapFramebuffer() @@ -38,7 +42,7 @@ OmapFramebuffer::~OmapFramebuffer() Destroy(); } -void OmapFramebuffer::Create() +void OmapFramebuffer::Create(Flags buffer_flags) { const PixelFormatInfo& format_info = get_pixel_format_info(m_format); @@ -50,13 +54,61 @@ void OmapFramebuffer::Create() uint32_t flags = OMAP_BO_SCANOUT | OMAP_BO_WC; - uint32_t size = width() * height() * pi.bitspp / 8; - - struct omap_bo* bo = omap_bo_new(m_omap_card.dev(), size, flags); - if (!bo) - throw invalid_argument(string("omap_bo_new failed: ") + strerror(errno)); - - uint32_t stride = width() * pi.bitspp / 8; +#if defined(OMAP_BO_MEM_CONTIG) + if (buffer_flags & Flags::MemContig) + flags |= OMAP_BO_MEM_CONTIG; + if (buffer_flags & Flags::MemTiler) + flags |= OMAP_BO_MEM_TILER; + if (buffer_flags & Flags::MemPin) + flags |= OMAP_BO_MEM_PIN; +#endif + + struct omap_bo* bo; + + uint32_t stride; + + if (!(buffer_flags & Flags::Tiled)) { + stride = width() * pi.bitspp / 8; + + uint32_t size = stride * height() / pi.ysub; + + bo = omap_bo_new(m_omap_card.dev(), size, flags); + if (!bo) + throw invalid_argument(string("omap_bo_new failed: ") + strerror(errno)); + } else { + unsigned bitspertiler; + + switch (m_format) { + case PixelFormat::NV12: + bitspertiler = i == 0 ? 8 : 16; break; + case PixelFormat::YUYV: + case PixelFormat::UYVY: + bitspertiler = 32; break; + case PixelFormat::ARGB8888: + case PixelFormat::XRGB8888: + bitspertiler = 32; break; + case PixelFormat::RGB565: + bitspertiler = 16; break; + default: + throw invalid_argument("unimplemented format"); + } + + switch (bitspertiler) { + case 8: flags |= OMAP_BO_TILED_8; break; + case 16: flags |= OMAP_BO_TILED_16; break; + case 32: flags |= OMAP_BO_TILED_32; break; + default: + throw invalid_argument("bad bitspertiler"); + } + + uint32_t width_tiler = width() * pi.bitspp / bitspertiler; + + bo = omap_bo_new_tiled(m_omap_card.dev(), width_tiler, height(), flags); + if (!bo) + throw invalid_argument(string("omap_bo_new_tiled failed: ") + strerror(errno)); + + stride = round_up(width() * pi.bitspp / 8, PAGE_SIZE); + } plane.omap_bo = bo; plane.handle = omap_bo_handle(bo); @@ -67,7 +119,7 @@ void OmapFramebuffer::Create() plane.prime_fd = -1; } - /* create framebuffer object for the dumb-buffer */ + /* create framebuffer object */ uint32_t bo_handles[4] = { m_planes[0].handle, m_planes[1].handle }; uint32_t pitches[4] = { m_planes[0].stride, m_planes[1].stride }; uint32_t offsets[4] = { m_planes[0].offset, m_planes[1].offset }; @@ -82,6 +134,7 @@ void OmapFramebuffer::Create() void OmapFramebuffer::Destroy() { + /* delete framebuffer */ drmModeRmFB(card().fd(), id()); for (uint i = 0; i < m_num_planes; ++i) { diff --git a/py/pykms/__init__.py b/py/pykms/__init__.py index 41c1219..3b5f743 100644 --- a/py/pykms/__init__.py +++ b/py/pykms/__init__.py @@ -16,6 +16,20 @@ white = RGB(255, 255, 255) cyan = RGB(0, 255, 255) # +# Rotation enum +# + +class Rotation(int, Enum): + ROTATE_0 = 1 << 0 + ROTATE_90 = 1 << 1 + ROTATE_180 = 1 << 2 + ROTATE_270 = 1 << 3 + ROTATE_MASK = ROTATE_0 | ROTATE_90 | ROTATE_180 | ROTATE_270 + REFLECT_X = 1 << 4 + REFLECT_Y = 1 << 5 + REFLECT_MASK = REFLECT_X | REFLECT_Y + +# # DrmObject API extensions # diff --git a/py/pykms/pykmsomap.cpp b/py/pykms/pykmsomap.cpp index 7480c78..0c3a8ee 100644 --- a/py/pykms/pykmsomap.cpp +++ b/py/pykms/pykmsomap.cpp @@ -14,11 +14,25 @@ void init_pykmsomap(py::module &m) .def(py::init<>()) ; - py::class_<OmapFramebuffer>(m, "OmapFramebuffer", py::base<MappedFramebuffer>()) - .def(py::init<OmapCard&, uint32_t, uint32_t, const string&>(), - py::keep_alive<1, 2>()) // Keep Card alive until this is destructed - .def(py::init<OmapCard&, uint32_t, uint32_t, PixelFormat>(), - py::keep_alive<1, 2>()) // Keep OmapCard alive until this is destructed + py::class_<OmapFramebuffer> omapfb(m, "OmapFramebuffer", py::base<MappedFramebuffer>()); + + // 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") + .value("None", OmapFramebuffer::Flags::None) + .value("Tiled", OmapFramebuffer::Flags::Tiled) + .value("MemContig", OmapFramebuffer::Flags::MemContig) + .value("MemTiler", OmapFramebuffer::Flags::MemTiler) + .value("MemPin", OmapFramebuffer::Flags::MemPin) + .export_values() + ; + + omapfb + .def(py::init<OmapCard&, uint32_t, uint32_t, const string&, OmapFramebuffer::Flags>(), + py::keep_alive<1, 2>(), // Keep Card alive until this is destructed + py::arg("card"), py::arg("width"), py::arg("height"), py::arg("fourcc"), py::arg("flags") = OmapFramebuffer::None) + .def(py::init<OmapCard&, uint32_t, uint32_t, PixelFormat, OmapFramebuffer::Flags>(), + py::keep_alive<1, 2>(), // Keep OmapCard alive until this is destructed + py::arg("card"), py::arg("width"), py::arg("height"), py::arg("pixfmt"), py::arg("flags") = OmapFramebuffer::None) .def_property_readonly("format", &OmapFramebuffer::format) .def_property_readonly("num_planes", &OmapFramebuffer::num_planes) .def("fd", &OmapFramebuffer::prime_fd) diff --git a/py/tests/cam.py b/py/tests/cam.py index 57d0c1a..c813b2f 100755 --- a/py/tests/cam.py +++ b/py/tests/cam.py @@ -8,11 +8,6 @@ w = 640 h = 480 fmt = pykms.PixelFormat.YUYV - -# This hack makes drm initialize the fbcon, setting up the default connector -card = pykms.Card() -card = 0 - card = pykms.Card() res = pykms.ResourceManager(card) conn = res.reserve_connector() @@ -20,6 +15,13 @@ crtc = res.reserve_crtc(conn) plane = res.reserve_overlay_plane(crtc, fmt) mode = conn.get_default_mode() +modeb = mode.to_blob(card) + +req = pykms.AtomicReq(card) +req.add(conn, "CRTC_ID", crtc.id) +req.add(crtc, {"ACTIVE": 1, + "MODE_ID": modeb.id}) +req.commit_sync(allow_modeset = True) NUM_BUFS = 5 diff --git a/py/tests/rottest.py b/py/tests/rottest.py new file mode 100755 index 0000000..8988134 --- /dev/null +++ b/py/tests/rottest.py @@ -0,0 +1,171 @@ +#!/usr/bin/python3 + +import pykms +from enum import Enum + +import termios, sys, os, tty + +card = pykms.OmapCard() + +res = pykms.ResourceManager(card) +conn = res.reserve_connector() +crtc = res.reserve_crtc(conn) +mode = conn.get_default_mode() +modeb = mode.to_blob(card) +rootplane = res.reserve_primary_plane(crtc, pykms.PixelFormat.XRGB8888) +plane = res.reserve_overlay_plane(crtc, pykms.PixelFormat.NV12) + +card.disable_planes() + +req = pykms.AtomicReq(card) + +req.add(conn, "CRTC_ID", crtc.id) + +req.add(crtc, {"ACTIVE": 1, + "MODE_ID": modeb.id}) + +# This enables the root plane + +#rootfb = pykms.OmapFramebuffer(card, mode.hdisplay, mode.vdisplay, "XR24"); +#pykms.draw_test_pattern(rootfb); +# +#req.add(rootplane, {"FB_ID": rootfb.id, +# "CRTC_ID": crtc.id, +# "SRC_X": 0 << 16, +# "SRC_Y": 0 << 16, +# "SRC_W": mode.hdisplay << 16, +# "SRC_H": mode.vdisplay << 16, +# "CRTC_X": 0, +# "CRTC_Y": 0, +# "CRTC_W": mode.hdisplay, +# "CRTC_H": mode.vdisplay, +# "zorder": 0}) + +req.commit_sync(allow_modeset = True) + +def show_rot_plane(crtc, plane, fb, rot, x_scale, y_scale): + + crtc_w = int(fb_w * x_scale) + crtc_h = int(fb_h * y_scale) + + if (rot & pykms.Rotation.ROTATE_90) or (rot & pykms.Rotation.ROTATE_270): + tmp = crtc_w + crtc_w = crtc_h + crtc_h = tmp + + crtc_x = int(mode.hdisplay / 2 - crtc_w / 2) + crtc_y = int(mode.vdisplay / 2 - crtc_h / 2) + + req = pykms.AtomicReq(card) + + src_x = 0 + src_y = 0 + src_w = fb_w - src_x + src_h = fb_h - src_y + + print("SRC {},{}-{}x{} DST {},{}-{}x{}".format( + src_x, src_y, src_w, src_h, + crtc_x, crtc_y, crtc_w, crtc_h)) + + angle_str = pykms.Rotation(rot & pykms.Rotation.ROTATE_MASK).name + reflect_x_str = "REFLECT_X" if rot & pykms.Rotation.REFLECT_X else "" + reflect_y_str = "REFLECT_Y" if rot & pykms.Rotation.REFLECT_Y else "" + + print("{} {} {}".format(angle_str, reflect_x_str, reflect_y_str)) + + sys.stdout.flush() + + req.add(plane, {"FB_ID": fb.id, + "CRTC_ID": crtc.id, + "SRC_X": src_x << 16, + "SRC_Y": src_y << 16, + "SRC_W": src_w << 16, + "SRC_H": src_h << 16, + "CRTC_X": crtc_x, + "CRTC_Y": crtc_y, + "CRTC_W": crtc_w, + "CRTC_H": crtc_h, + "rotation": rot, + "zorder": 2}) + + req.commit_sync(allow_modeset = True) + + +fb_w = 480 +fb_h = 150 +x_scale = 1 +y_scale = 1 + +fb = pykms.OmapFramebuffer(card, fb_w, fb_h, "NV12", flags = pykms.OmapFramebuffer.Tiled); +#fb = pykms.DumbFramebuffer(card, fb_w, fb_h, "NV12") +pykms.draw_test_pattern(fb); + +def even(i): + return i & ~1 + +pykms.draw_text(fb, even((fb_w // 2) - (8 * 3) // 2), 4, "TOP", pykms.white) +pykms.draw_text(fb, even((fb_w // 2) - (8 * 6) // 2), fb_h - 8 - 4, "BOTTOM", pykms.white) +pykms.draw_text(fb, 4, even(((fb_h // 2) - 4)), "L", pykms.white) +pykms.draw_text(fb, fb_w - 8 - 4, even(((fb_h // 2) - 4)), "R", pykms.white) + +rots = [ pykms.Rotation.ROTATE_0, pykms.Rotation.ROTATE_90, pykms.Rotation.ROTATE_180, pykms.Rotation.ROTATE_270 ] +cursors = [ "A", "D", "B", "C" ] + +print("Use the cursor keys, x and y to change rotation. Press q to quit.") + +fd = sys.stdin.fileno() +oldterm = termios.tcgetattr(fd) +tty.setcbreak(fd) + +try: + esc_seq = 0 + + current_rot = pykms.Rotation.ROTATE_0 + + show_rot_plane(crtc, plane, fb, current_rot, x_scale, y_scale) + + while True: + c = sys.stdin.read(1) + #print("Got character {}".format(repr(c))) + + changed = False + handled = False + + if esc_seq == 0: + if c == "\x1b": + esc_seq = 1 + handled = True + elif esc_seq == 1: + if c == "[": + esc_seq = 2 + handled = True + else: + esc_seq = 0 + elif esc_seq == 2: + esc_seq = 0 + + if c in cursors: + handled = True + + rot = rots[cursors.index(c)] + + current_rot &= ~pykms.Rotation.ROTATE_MASK + current_rot |= rot + + changed = True + + if not handled: + if c == "q": + break + elif c == "x": + current_rot ^= pykms.Rotation.REFLECT_X + changed = True + elif c == "y": + current_rot ^= pykms.Rotation.REFLECT_Y + changed = True + + if changed: + show_rot_plane(crtc, plane, fb, current_rot, x_scale, y_scale) + +finally: + termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm) |