summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kms++/inc/kms++/omap/omapframebuffer.h15
-rw-r--r--kms++/src/omap/omapframebuffer.cpp81
-rw-r--r--py/pykms/__init__.py14
-rw-r--r--py/pykms/pykmsomap.cpp24
-rwxr-xr-xpy/tests/cam.py12
-rwxr-xr-xpy/tests/rottest.py171
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)