Snap for 5907899 from fcf03f84cf07ec30816bd6257e9a0aa7f228a497 to r-keystone-qcom-release
Change-Id: I49bd0e12aefe9048b3f9370d18096cdfa4f32bc1
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 57088bc..f2f24fe 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -25,6 +25,8 @@
set(KMSXX_ENABLE_KMSCUBE OFF CACHE BOOL "Enable kmscube")
+set(KMSXX_ENABLE_THREADING ON CACHE BOOL "Enable threading for parallelized drawing")
+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wall")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra -Wno-unused-parameter")
diff --git a/METADATA b/METADATA
index 18cb362..e098fe8 100644
--- a/METADATA
+++ b/METADATA
@@ -1,9 +1,5 @@
name: "kms++"
-description:
- "libkmsxx is a small C++11 library for kernel mode setting. It tries to "
- "implement as little extra as possible while bringing the kms API in a C++ "
- "form to the user. It only implements a subset of what libdrm supports."
-
+description: "libkmsxx is a small C++11 library for kernel mode setting. It tries to implement as little extra as possible while bringing the kms API in a C++ form to the user. It only implements a subset of what libdrm supports."
third_party {
url {
type: HOMEPAGE
@@ -13,7 +9,11 @@
type: GIT
value: "https://github.com/tomba/kmsxx"
}
- version: "e0067bdc75566629c9143818c8f3970c16c8825e"
- last_upgrade_date { year: 2018 month: 8 day: 15 }
+ version: "a5545df02b40414c2bf3abc60cf629c5f59d00ec"
license_type: RECIPROCAL
+ last_upgrade_date {
+ year: 2019
+ month: 7
+ day: 30
+ }
}
diff --git a/README.md b/README.md
index f0f3b97..feb43d7 100644
--- a/README.md
+++ b/README.md
@@ -88,6 +88,8 @@
--------------------------------- | -------------
KMSXX_DISABLE_UNIVERSAL_PLANES | Set to disable the use of universal planes
KMSXX_DISABLE_ATOMIC | Set to disable the use of atomic modesetting
+KMSXX_DEVICE | Path to the card device node to use
+KMSXX_DRIVER | Name of the driver to use. The format is either "drvname" or "drvname:idx"
## Python notes
diff --git a/ext/pybind11 b/ext/pybind11
index 086d53e..9a19306 160000
--- a/ext/pybind11
+++ b/ext/pybind11
@@ -1 +1 @@
-Subproject commit 086d53e8c66a84d0ec723d5435918c76edd878e8
+Subproject commit 9a19306fbf30642ca331d0ec88e7da54a96860f9
diff --git a/kms++/inc/kms++/card.h b/kms++/inc/kms++/card.h
index c86278d..099d5b5 100644
--- a/kms++/inc/kms++/card.h
+++ b/kms++/inc/kms++/card.h
@@ -3,6 +3,7 @@
#include <cstdint>
#include <vector>
#include <map>
+#include <memory>
#include "decls.h"
#include "pipeline.h"
@@ -13,8 +14,8 @@
{
friend class Framebuffer;
public:
- Card();
- Card(const std::string& device);
+ Card(const std::string& dev_path = "");
+ Card(const std::string& driver, uint32_t idx);
virtual ~Card();
Card(const Card& other) = delete;
@@ -33,9 +34,11 @@
Plane* get_plane(uint32_t id) const;
Property* get_prop(uint32_t id) const;
- bool master() const { return m_master; }
+ bool is_master() const { return m_is_master; }
bool has_atomic() const { return m_has_atomic; }
bool has_has_universal_planes() const { return m_has_universal_planes; }
+ bool has_dumb_buffers() const { return m_has_dumb; }
+ bool has_kms() const;
const std::vector<Connector*> get_connectors() const { return m_connectors; }
const std::vector<Encoder*> get_encoders() const { return m_encoders; }
@@ -51,7 +54,10 @@
int disable_all();
+ const std::string& version_name() const { return m_version_name; }
+
private:
+ void setup();
void restore_modes();
std::map<uint32_t, DrmObject*> m_obmap;
@@ -64,9 +70,17 @@
std::vector<Framebuffer*> m_framebuffers;
int m_fd;
- bool m_master;
+ bool m_is_master;
bool m_has_atomic;
bool m_has_universal_planes;
+ bool m_has_dumb;
+
+ int m_version_major;
+ int m_version_minor;
+ int m_version_patchlevel;
+ std::string m_version_name;
+ std::string m_version_date;
+ std::string m_version_desc;
};
}
diff --git a/kms++/inc/kms++/connector.h b/kms++/inc/kms++/connector.h
index 3407730..155f916 100644
--- a/kms++/inc/kms++/connector.h
+++ b/kms++/inc/kms++/connector.h
@@ -10,6 +10,13 @@
struct ConnectorPriv;
+enum class ConnectorStatus
+{
+ Unknown,
+ Connected,
+ Disconnected,
+};
+
class Connector : public DrmPropObject
{
friend class Card;
@@ -24,7 +31,9 @@
Crtc* get_current_crtc() const;
std::vector<Crtc*> get_possible_crtcs() const;
+ // true if connected or unknown
bool connected() const;
+ ConnectorStatus connector_status() const;
const std::string& fullname() const { return m_fullname; }
uint32_t connector_type() const;
diff --git a/kms++/inc/kms++/drmpropobject.h b/kms++/inc/kms++/drmpropobject.h
index 38de584..d9ba58e 100644
--- a/kms++/inc/kms++/drmpropobject.h
+++ b/kms++/inc/kms++/drmpropobject.h
@@ -23,6 +23,7 @@
const std::map<uint32_t, uint64_t>& get_prop_map() const { return m_prop_values; }
+ int set_prop_value(Property* prop, uint64_t value);
int set_prop_value(uint32_t id, uint64_t value);
int set_prop_value(const std::string& name, uint64_t value);
diff --git a/kms++/inc/kms++/omap/omapcard.h b/kms++/inc/kms++/omap/omapcard.h
index 5c2f3a5..2f1f528 100644
--- a/kms++/inc/kms++/omap/omapcard.h
+++ b/kms++/inc/kms++/omap/omapcard.h
@@ -9,8 +9,7 @@
class OmapCard : public Card
{
public:
- OmapCard();
- OmapCard(const std::string& device);
+ OmapCard(const std::string& device = "");
virtual ~OmapCard();
struct omap_device* dev() const { return m_omap_dev; }
diff --git a/kms++/inc/kms++/pixelformats.h b/kms++/inc/kms++/pixelformats.h
index 6392de1..15fee7f 100644
--- a/kms++/inc/kms++/pixelformats.h
+++ b/kms++/inc/kms++/pixelformats.h
@@ -24,14 +24,32 @@
XRGB8888 = MakeFourCC("XR24"),
XBGR8888 = MakeFourCC("XB24"),
+ RGBX8888 = MakeFourCC("RX24"),
+ BGRX8888 = MakeFourCC("BX24"),
+
ARGB8888 = MakeFourCC("AR24"),
ABGR8888 = MakeFourCC("AB24"),
+ RGBA8888 = MakeFourCC("RA24"),
+ BGRA8888 = MakeFourCC("BA24"),
RGB888 = MakeFourCC("RG24"),
BGR888 = MakeFourCC("BG24"),
RGB565 = MakeFourCC("RG16"),
BGR565 = MakeFourCC("BG16"),
+
+ ARGB4444 = MakeFourCC("AR12"),
+ ARGB1555 = MakeFourCC("AR15"),
+
+ XRGB2101010 = MakeFourCC("XR30"),
+ XBGR2101010 = MakeFourCC("XB30"),
+ RGBX1010102 = MakeFourCC("RX30"),
+ BGRX1010102 = MakeFourCC("BX30"),
+
+ ARGB2101010 = MakeFourCC("AR30"),
+ ABGR2101010 = MakeFourCC("AB30"),
+ RGBA1010102 = MakeFourCC("RA30"),
+ BGRA1010102 = MakeFourCC("BA30"),
};
static inline PixelFormat FourCCToPixelFormat(const std::string& fourcc)
@@ -49,6 +67,12 @@
return std::string(buf);
}
+enum class PixelColorType
+{
+ RGB,
+ YUV,
+};
+
struct PixelFormatPlaneInfo
{
uint8_t bitspp;
@@ -58,6 +82,7 @@
struct PixelFormatInfo
{
+ PixelColorType type;
uint8_t num_planes;
struct PixelFormatPlaneInfo planes[4];
};
diff --git a/kms++/src/card.cpp b/kms++/src/card.cpp
index d71db7c..8de8b82 100644
--- a/kms++/src/card.cpp
+++ b/kms++/src/card.cpp
@@ -6,6 +6,8 @@
#include <string.h>
#include <algorithm>
#include <cerrno>
+#include <algorithm>
+#include <glob.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
@@ -17,23 +19,150 @@
namespace kms
{
-Card::Card()
- : Card("/dev/dri/card0")
+static vector<string> glob(const string& pattern)
{
+ glob_t glob_result;
+ memset(&glob_result, 0, sizeof(glob_result));
+
+ int r = glob(pattern.c_str(), 0, NULL, &glob_result);
+ if(r != 0) {
+ globfree(&glob_result);
+ throw runtime_error("failed to find DRM cards");
+ }
+
+ vector<string> filenames;
+ for(size_t i = 0; i < glob_result.gl_pathc; ++i)
+ filenames.push_back(string(glob_result.gl_pathv[i]));
+
+ globfree(&glob_result);
+
+ return filenames;
}
-
-Card::Card(const std::string& device)
+static int open_first_kms_device()
{
- int fd = open(device.c_str(), O_RDWR | O_CLOEXEC);
+ vector<string> paths = glob("/dev/dri/card*");
+
+ for (const string& path : paths) {
+ int fd = open(path.c_str(), O_RDWR | O_CLOEXEC);
+ if (fd < 0)
+ throw invalid_argument(string(strerror(errno)) + " opening device " + path);
+
+ auto res = drmModeGetResources(fd);
+ if (!res) {
+ close(fd);
+ continue;
+ }
+
+ bool has_kms = res->count_crtcs > 0 && res->count_connectors > 0 && res->count_encoders > 0;
+
+ drmModeFreeResources(res);
+
+ if (has_kms)
+ return fd;
+
+ close(fd);
+ }
+
+ throw runtime_error("No modesetting DRM card found");
+}
+
+static int open_device_by_path(string path)
+{
+ int fd = open(path.c_str(), O_RDWR | O_CLOEXEC);
if (fd < 0)
- throw invalid_argument(string(strerror(errno)) + " opening " + device);
- m_fd = fd;
+ throw invalid_argument(string(strerror(errno)) + " opening device " + path);
+ return fd;
+}
+
+// open Nth DRM card with the given driver name
+static int open_device_by_driver(string name, uint32_t idx)
+{
+ transform(name.begin(), name.end(), name.begin(), ::tolower);
+
+ uint32_t num_matches = 0;
+ vector<string> paths = glob("/dev/dri/card*");
+
+ for (const string& path : paths) {
+ int fd = open_device_by_path(path);
+
+ drmVersionPtr ver = drmGetVersion(fd);
+ string drv_name = string(ver->name, ver->name_len);
+ drmFreeVersion(ver);
+
+ transform(drv_name.begin(), drv_name.end(), drv_name.begin(), ::tolower);
+
+ if (name == drv_name) {
+ if (idx == num_matches)
+ return fd;
+ num_matches++;
+ }
+
+ close(fd);
+ }
+
+ throw invalid_argument("Failed to find a DRM device " + name + ":" + to_string(idx));
+}
+
+Card::Card(const std::string& dev_path)
+{
+ const char* drv_p = getenv("KMSXX_DRIVER");
+ const char* dev_p = getenv("KMSXX_DEVICE");
+
+ if (!dev_path.empty()) {
+ m_fd = open_device_by_path(dev_path);
+ } else if (dev_p) {
+ string dev(dev_p);
+ m_fd = open_device_by_path(dev);
+ } else if (drv_p) {
+ string drv(drv_p);
+
+ auto isplit = find(drv.begin(), drv.end(), ':');
+
+ if (isplit == drv.begin())
+ throw runtime_error("Invalid KMSXX_DRIVER");
+
+ string name;
+ uint32_t num = 0;
+
+ if (isplit == drv.end()) {
+ name = drv;
+ } else {
+ name = string(drv.begin(), isplit);
+ string numstr = string(isplit + 1, drv.end());
+ num = stoul(numstr);
+ }
+
+ m_fd = open_device_by_driver(name, num);
+ } else {
+ m_fd = open_first_kms_device();
+ }
+
+ setup();
+}
+
+Card::Card(const std::string& driver, uint32_t idx)
+{
+ m_fd = open_device_by_driver(driver, idx);
+
+ setup();
+}
+
+void Card::setup()
+{
+ drmVersionPtr ver = drmGetVersion(m_fd);
+ m_version_major = ver->version_major;
+ m_version_minor = ver->version_minor;
+ m_version_patchlevel = ver->version_patchlevel;
+ m_version_name = string(ver->name, ver->name_len);
+ m_version_date = string(ver->date, ver->date_len);
+ m_version_desc = string(ver->desc, ver->desc_len);
+ drmFreeVersion(ver);
int r;
- r = drmSetMaster(fd);
- m_master = r == 0;
+ r = drmSetMaster(m_fd);
+ m_is_master = r == 0;
if (getenv("KMSXX_DISABLE_UNIVERSAL_PLANES") == 0) {
r = drmSetClientCap(m_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
@@ -54,48 +183,47 @@
#endif
uint64_t has_dumb;
- r = drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb);
- if (r || !has_dumb)
- throw invalid_argument("Dumb buffers not available");
+ r = drmGetCap(m_fd, DRM_CAP_DUMB_BUFFER, &has_dumb);
+ m_has_dumb = r == 0 && has_dumb;
auto res = drmModeGetResources(m_fd);
- if (!res)
- throw invalid_argument("Can't get card resources");
+ if (res) {
+ for (int i = 0; i < res->count_connectors; ++i) {
+ uint32_t id = res->connectors[i];
+ auto ob = new Connector(*this, id, i);
+ m_obmap[id] = ob;
+ m_connectors.push_back(ob);
+ }
- for (int i = 0; i < res->count_connectors; ++i) {
- uint32_t id = res->connectors[i];
- auto ob = new Connector(*this, id, i);
- m_obmap[id] = ob;
- m_connectors.push_back(ob);
+ for (int i = 0; i < res->count_crtcs; ++i) {
+ uint32_t id = res->crtcs[i];
+ auto ob = new Crtc(*this, id, i);
+ m_obmap[id] = ob;
+ m_crtcs.push_back(ob);
+ }
+
+ for (int i = 0; i < res->count_encoders; ++i) {
+ uint32_t id = res->encoders[i];
+ auto ob = new Encoder(*this, id, i);
+ m_obmap[id] = ob;
+ m_encoders.push_back(ob);
+ }
+
+ drmModeFreeResources(res);
+
+ auto planeRes = drmModeGetPlaneResources(m_fd);
+ if (planeRes) {
+ for (uint i = 0; i < planeRes->count_planes; ++i) {
+ uint32_t id = planeRes->planes[i];
+ auto ob = new Plane(*this, id, i);
+ m_obmap[id] = ob;
+ m_planes.push_back(ob);
+ }
+
+ drmModeFreePlaneResources(planeRes);
+ }
}
- for (int i = 0; i < res->count_crtcs; ++i) {
- uint32_t id = res->crtcs[i];
- auto ob = new Crtc(*this, id, i);
- m_obmap[id] = ob;
- m_crtcs.push_back(ob);
- }
-
- for (int i = 0; i < res->count_encoders; ++i) {
- uint32_t id = res->encoders[i];
- auto ob = new Encoder(*this, id, i);
- m_obmap[id] = ob;
- m_encoders.push_back(ob);
- }
-
- drmModeFreeResources(res);
-
- auto planeRes = drmModeGetPlaneResources(m_fd);
-
- for (uint i = 0; i < planeRes->count_planes; ++i) {
- uint32_t id = planeRes->planes[i];
- auto ob = new Plane(*this, id, i);
- m_obmap[id] = ob;
- m_planes.push_back(ob);
- }
-
- drmModeFreePlaneResources(planeRes);
-
// collect all possible props
for (auto ob : get_objects()) {
auto props = drmModeObjectGetProperties(m_fd, ob->id(), ob->object_type());
@@ -136,6 +264,12 @@
void Card::drop_master()
{
drmDropMaster(fd());
+ m_is_master = false;
+}
+
+bool Card::has_kms() const
+{
+ return m_connectors.size() > 0 && m_encoders.size() > 0 && m_crtcs.size() > 0;
}
void Card::restore_modes()
diff --git a/kms++/src/connector.cpp b/kms++/src/connector.cpp
index 47759be..a1807da 100644
--- a/kms++/src/connector.cpp
+++ b/kms++/src/connector.cpp
@@ -195,6 +195,18 @@
m_priv->drm_connector->connection == DRM_MODE_UNKNOWNCONNECTION;
}
+ConnectorStatus Connector::connector_status() const
+{
+ switch (m_priv->drm_connector->connection) {
+ case DRM_MODE_CONNECTED:
+ return ConnectorStatus::Connected;
+ case DRM_MODE_DISCONNECTED:
+ return ConnectorStatus::Disconnected;
+ default:
+ return ConnectorStatus::Unknown;
+ }
+}
+
vector<Crtc*> Connector::get_possible_crtcs() const
{
vector<Crtc*> crtcs;
diff --git a/kms++/src/drmpropobject.cpp b/kms++/src/drmpropobject.cpp
index f5a3c97..f91f913 100644
--- a/kms++/src/drmpropobject.cpp
+++ b/kms++/src/drmpropobject.cpp
@@ -80,6 +80,11 @@
return unique_ptr<Blob>(new Blob(card(), blob_id));
}
+int DrmPropObject::set_prop_value(Property* prop, uint64_t value)
+{
+ return drmModeObjectSetProperty(card().fd(), this->id(), this->object_type(), prop->id(), value);
+}
+
int DrmPropObject::set_prop_value(uint32_t id, uint64_t value)
{
return drmModeObjectSetProperty(card().fd(), this->id(), this->object_type(), id, value);
diff --git a/kms++/src/encoder.cpp b/kms++/src/encoder.cpp
index 9cd5304..bfb2ea8 100644
--- a/kms++/src/encoder.cpp
+++ b/kms++/src/encoder.cpp
@@ -28,6 +28,7 @@
DEF_ENC(VIRTUAL),
DEF_ENC(DSI),
{ 7, "DPMST" },
+ { 8, "DPI" },
#undef DEF_ENC
};
diff --git a/kms++/src/omap/omapcard.cpp b/kms++/src/omap/omapcard.cpp
index e811b6d..5e21c75 100644
--- a/kms++/src/omap/omapcard.cpp
+++ b/kms++/src/omap/omapcard.cpp
@@ -9,11 +9,6 @@
namespace kms
{
-OmapCard::OmapCard()
- : OmapCard("/dev/dri/card0")
-{
-
-}
OmapCard::OmapCard(const string& device)
: Card(device)
diff --git a/kms++/src/pixelformats.cpp b/kms++/src/pixelformats.cpp
index 84ea924..ecca41d 100644
--- a/kms++/src/pixelformats.cpp
+++ b/kms++/src/pixelformats.cpp
@@ -8,28 +8,49 @@
{
static const map<PixelFormat, PixelFormatInfo> format_info_array = {
/* YUV packed */
- { PixelFormat::UYVY, { 1, { { 16, 2, 1 } }, } },
- { PixelFormat::YUYV, { 1, { { 16, 2, 1 } }, } },
- { PixelFormat::YVYU, { 1, { { 16, 2, 1 } }, } },
- { PixelFormat::VYUY, { 1, { { 16, 2, 1 } }, } },
+ { PixelFormat::UYVY, { PixelColorType::YUV, 1, { { 16, 2, 1 } }, } },
+ { PixelFormat::YUYV, { PixelColorType::YUV, 1, { { 16, 2, 1 } }, } },
+ { PixelFormat::YVYU, { PixelColorType::YUV, 1, { { 16, 2, 1 } }, } },
+ { PixelFormat::VYUY, { PixelColorType::YUV, 1, { { 16, 2, 1 } }, } },
/* YUV semi-planar */
- { PixelFormat::NV12, { 2, { { 8, 1, 1, }, { 8, 2, 2 } }, } },
- { PixelFormat::NV21, { 2, { { 8, 1, 1, }, { 8, 2, 2 } }, } },
+ { PixelFormat::NV12, { PixelColorType::YUV, 2, { { 8, 1, 1, }, { 8, 2, 2 } }, } },
+ { PixelFormat::NV21, { PixelColorType::YUV, 2, { { 8, 1, 1, }, { 8, 2, 2 } }, } },
/* RGB16 */
- { PixelFormat::RGB565, { 1, { { 16, 1, 1 } }, } },
- { PixelFormat::BGR565, { 1, { { 16, 1, 1 } }, } },
+ { PixelFormat::RGB565, { PixelColorType::RGB, 1, { { 16, 1, 1 } }, } },
+ { PixelFormat::BGR565, { PixelColorType::RGB, 1, { { 16, 1, 1 } }, } },
/* RGB24 */
- { PixelFormat::RGB888, { 1, { { 24, 1, 1 } }, } },
- { PixelFormat::BGR888, { 1, { { 24, 1, 1 } }, } },
+ { PixelFormat::RGB888, { PixelColorType::RGB, 1, { { 24, 1, 1 } }, } },
+ { PixelFormat::BGR888, { PixelColorType::RGB, 1, { { 24, 1, 1 } }, } },
/* RGB32 */
- { PixelFormat::XRGB8888, { 1, { { 32, 1, 1 } }, } },
- { PixelFormat::XBGR8888, { 1, { { 32, 1, 1 } }, } },
- { PixelFormat::ARGB8888, { 1, { { 32, 1, 1 } }, } },
- { PixelFormat::ABGR8888, { 1, { { 32, 1, 1 } }, } },
+ { PixelFormat::XRGB8888, { PixelColorType::RGB, 1, { { 32, 1, 1 } }, } },
+ { PixelFormat::XBGR8888, { PixelColorType::RGB, 1, { { 32, 1, 1 } }, } },
+ { PixelFormat::RGBX8888, { PixelColorType::RGB, 1, { { 32, 1, 1 } }, } },
+ { PixelFormat::BGRX8888, { PixelColorType::RGB, 1, { { 32, 1, 1 } }, } },
+
+ { PixelFormat::ARGB8888, { PixelColorType::RGB, 1, { { 32, 1, 1 } }, } },
+ { PixelFormat::ABGR8888, { PixelColorType::RGB, 1, { { 32, 1, 1 } }, } },
+ { PixelFormat::RGBA8888, { PixelColorType::RGB, 1, { { 32, 1, 1 } }, } },
+ { PixelFormat::BGRA8888, { PixelColorType::RGB, 1, { { 32, 1, 1 } }, } },
+
+ { PixelFormat::XRGB2101010, { PixelColorType::RGB, 1, { { 32, 1, 1 } }, } },
+ { PixelFormat::XBGR2101010, { PixelColorType::RGB, 1, { { 32, 1, 1 } }, } },
+ { PixelFormat::RGBX1010102, { PixelColorType::RGB, 1, { { 32, 1, 1 } }, } },
+ { PixelFormat::BGRX1010102, { PixelColorType::RGB, 1, { { 32, 1, 1 } }, } },
+
+ { PixelFormat::ARGB2101010, { PixelColorType::RGB, 1, { { 32, 1, 1 } }, } },
+ { PixelFormat::ABGR2101010, { PixelColorType::RGB, 1, { { 32, 1, 1 } }, } },
+ { PixelFormat::RGBA1010102, { PixelColorType::RGB, 1, { { 32, 1, 1 } }, } },
+ { PixelFormat::BGRA1010102, { PixelColorType::RGB, 1, { { 32, 1, 1 } }, } },
+
+ { PixelFormat::ARGB4444, { PixelColorType::RGB, 1, { { 16, 1, 1 } }, } },
+ { PixelFormat::ARGB1555, { PixelColorType::RGB, 1, { { 16, 1, 1 } }, } },
};
const struct PixelFormatInfo& get_pixel_format_info(PixelFormat format)
{
+ if (!format_info_array.count(format))
+ throw invalid_argument("get_pixel_format_info: Unsupported pixelformat");
+
return format_info_array.at(format);
}
diff --git a/kms++util/CMakeLists.txt b/kms++util/CMakeLists.txt
index 2fc15e3..70f3b17 100644
--- a/kms++util/CMakeLists.txt
+++ b/kms++util/CMakeLists.txt
@@ -7,7 +7,12 @@
$<INSTALL_INTERFACE:include>
PRIVATE src)
-target_link_libraries(kms++util kms++ pthread)
+target_link_libraries(kms++util kms++)
+
+if (KMSXX_ENABLE_THREADING)
+ target_link_libraries(kms++util pthread)
+ add_definitions(-DHAS_PTHREAD)
+endif()
set_target_properties(kms++util PROPERTIES
PUBLIC_HEADER "${PUB_HDRS}")
diff --git a/kms++util/inc/kms++util/color.h b/kms++util/inc/kms++util/color.h
index f378433..2bf6e66 100644
--- a/kms++util/inc/kms++util/color.h
+++ b/kms++util/inc/kms++util/color.h
@@ -25,8 +25,19 @@
uint32_t bgr888() const;
uint32_t argb8888() const;
uint32_t abgr8888() const;
+ uint32_t rgba8888() const;
+ uint32_t bgra8888() const;
+
+ // XXX these functions leave the lowest 2 bits zero
+ uint32_t argb2101010() const;
+ uint32_t abgr2101010() const;
+ uint32_t rgba1010102() const;
+ uint32_t bgra1010102() const;
+
uint16_t rgb565() const;
uint16_t bgr565() const;
+ uint16_t argb4444() const;
+ uint16_t argb1555() const;
YUV yuv(YUVType type = YUVType::BT601_Lim) const;
uint8_t b;
diff --git a/kms++util/inc/kms++util/kms++util.h b/kms++util/inc/kms++util/kms++util.h
index 8e45b0d..62ec663 100644
--- a/kms++util/inc/kms++util/kms++util.h
+++ b/kms++util/inc/kms++util/kms++util.h
@@ -22,6 +22,7 @@
void draw_yuv420_macropixel(IFramebuffer& buf, unsigned x, unsigned y,
YUV yuv1, YUV yuv2, YUV yuv3, YUV yuv4);
void draw_rect(IFramebuffer &fb, uint32_t x, uint32_t y, uint32_t w, uint32_t h, RGB color);
+void draw_circle(IFramebuffer& fb, int32_t xCenter, int32_t yCenter, int32_t radius, RGB color);
void draw_text(IFramebuffer& buf, uint32_t x, uint32_t y, const std::string& str, RGB color);
void draw_color_bar(IFramebuffer& buf, int old_xpos, int xpos, int width);
diff --git a/kms++util/inc/kms++util/videodevice.h b/kms++util/inc/kms++util/videodevice.h
index 68e2b01..e089bcd 100644
--- a/kms++util/inc/kms++util/videodevice.h
+++ b/kms++util/inc/kms++util/videodevice.h
@@ -71,6 +71,8 @@
std::vector<kms::PixelFormat> get_formats();
void set_format(kms::PixelFormat fmt, uint32_t width, uint32_t height);
+ void get_selection(uint32_t& left, uint32_t& top, uint32_t& width, uint32_t& height);
+ void set_selection(uint32_t& left, uint32_t& top, uint32_t& width, uint32_t& height);
void set_queue_size(uint32_t queue_size);
void queue(kms::DumbFramebuffer* fb);
kms::DumbFramebuffer* dequeue();
diff --git a/kms++util/src/color.cpp b/kms++util/src/color.cpp
index 2e6f217..80e4866 100644
--- a/kms++util/src/color.cpp
+++ b/kms++util/src/color.cpp
@@ -49,6 +49,36 @@
return (a << 24) | (b << 16) | (g << 8) | (r << 0);
}
+uint32_t RGB::rgba8888() const
+{
+ return (r << 24) | (g << 16) | (b << 8) | (a << 0);
+}
+
+uint32_t RGB::bgra8888() const
+{
+ return (b << 24) | (g << 16) | (r << 8) | (a << 0);
+}
+
+uint32_t RGB::argb2101010() const
+{
+ return ((a >> 6) << 30) | (r << 22) | (g << 12) | (b << 2);
+}
+
+uint32_t RGB::abgr2101010() const
+{
+ return ((a >> 6) << 30) | (b << 22) | (g << 12) | (r << 2);
+}
+
+uint32_t RGB::rgba1010102() const
+{
+ return (r << 24) | (g << 14) | (b << 4) | (a >> 6);
+}
+
+uint32_t RGB::bgra1010102() const
+{
+ return (b << 24) | (g << 14) | (r << 4) | (a >> 6);
+}
+
uint16_t RGB::rgb565() const
{
return ((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3) << 0);
@@ -59,6 +89,16 @@
return ((b >> 3) << 11) | ((g >> 2) << 5) | ((r >> 3) << 0);
}
+uint16_t RGB::argb4444() const
+{
+ return ((a >> 4) << 12) | ((r >> 4) << 8) | ((g >> 4) << 4) | ((b >> 4) << 0);
+}
+
+uint16_t RGB::argb1555() const
+{
+ return ((!!a) << 15) | ((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3) << 0);
+}
+
YUV RGB::yuv(YUVType type) const
{
return YUV(*this, type);
diff --git a/kms++util/src/drawing.cpp b/kms++util/src/drawing.cpp
index 4e5c6c1..194daf8 100644
--- a/kms++util/src/drawing.cpp
+++ b/kms++util/src/drawing.cpp
@@ -1,4 +1,6 @@
+#include <cmath>
+
#include <kms++/kms++.h>
#include <kms++util/kms++util.h>
@@ -26,6 +28,48 @@
*p = color.abgr8888();
break;
}
+ case PixelFormat::RGBX8888:
+ case PixelFormat::RGBA8888:
+ {
+ uint32_t *p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4);
+ *p = color.rgba8888();
+ break;
+ }
+ case PixelFormat::BGRX8888:
+ case PixelFormat::BGRA8888:
+ {
+ uint32_t *p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4);
+ *p = color.bgra8888();
+ break;
+ }
+ case PixelFormat::XRGB2101010:
+ case PixelFormat::ARGB2101010:
+ {
+ uint32_t *p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4);
+ *p = color.argb2101010();
+ break;
+ }
+ case PixelFormat::XBGR2101010:
+ case PixelFormat::ABGR2101010:
+ {
+ uint32_t *p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4);
+ *p = color.abgr2101010();
+ break;
+ }
+ case PixelFormat::RGBX1010102:
+ case PixelFormat::RGBA1010102:
+ {
+ uint32_t *p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4);
+ *p = color.rgba1010102();
+ break;
+ }
+ case PixelFormat::BGRX1010102:
+ case PixelFormat::BGRA1010102:
+ {
+ uint32_t *p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4);
+ *p = color.bgra1010102();
+ break;
+ }
case PixelFormat::RGB888:
{
uint8_t *p = buf.map(0) + buf.stride(0) * y + x * 3;
@@ -54,6 +98,18 @@
*p = color.bgr565();
break;
}
+ case PixelFormat::ARGB4444:
+ {
+ uint16_t *p = (uint16_t*)(buf.map(0) + buf.stride(0) * y + x * 2);
+ *p = color.argb4444();
+ break;
+ }
+ case PixelFormat::ARGB1555:
+ {
+ uint16_t *p = (uint16_t*)(buf.map(0) + buf.stride(0) * y + x * 2);
+ *p = color.argb1555();
+ break;
+ }
default:
throw std::invalid_argument("invalid pixelformat");
}
@@ -166,6 +222,8 @@
case PixelFormat::BGR888:
case PixelFormat::RGB565:
case PixelFormat::BGR565:
+ case PixelFormat::ARGB4444:
+ case PixelFormat::ARGB1555:
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++) {
draw_rgb_pixel(fb, x + i, y + j, color);
@@ -194,7 +252,23 @@
}
break;
default:
- throw std::invalid_argument("unknown pixelformat");
+ throw std::invalid_argument("draw_rect: unknown pixelformat");
+ }
+}
+
+void draw_horiz_line(IFramebuffer& fb, uint32_t x1, uint32_t x2, uint32_t y, RGB color)
+{
+ for (uint32_t x = x1; x <= x2; ++x)
+ draw_rgb_pixel(fb, x, y, color);
+}
+
+void draw_circle(IFramebuffer& fb, int32_t xCenter, int32_t yCenter, int32_t radius, RGB color)
+{
+ int32_t r2 = radius * radius;
+
+ for (int y = -radius; y <= radius; y++) {
+ int32_t x = (int)(sqrt(r2 - y * y) + 0.5);
+ draw_horiz_line(fb, xCenter - x, xCenter + x, yCenter - y, color);
}
}
@@ -222,6 +296,8 @@
case PixelFormat::BGR888:
case PixelFormat::RGB565:
case PixelFormat::BGR565:
+ case PixelFormat::ARGB4444:
+ case PixelFormat::ARGB1555:
for (y = 0; y < 8; y++) {
for (x = 0; x < 8; x++) {
bool b = get_char_pixel(c, x, y);
@@ -262,7 +338,7 @@
}
break;
default:
- throw std::invalid_argument("unknown pixelformat");
+ throw std::invalid_argument("draw_char: unknown pixelformat");
}
}
diff --git a/kms++util/src/testpat.cpp b/kms++util/src/testpat.cpp
index cf43d00..f9a3c8a 100644
--- a/kms++util/src/testpat.cpp
+++ b/kms++util/src/testpat.cpp
@@ -3,7 +3,10 @@
#include <cstring>
#include <cassert>
+
+#ifdef HAS_PTHREAD
#include <thread>
+#endif
#include <kms++/kms++.h>
#include <kms++util/kms++util.h>
@@ -102,15 +105,10 @@
unsigned x, y;
unsigned w = fb.width();
- switch (fb.format()) {
- case PixelFormat::XRGB8888:
- case PixelFormat::XBGR8888:
- case PixelFormat::ARGB8888:
- case PixelFormat::ABGR8888:
- case PixelFormat::RGB888:
- case PixelFormat::BGR888:
- case PixelFormat::RGB565:
- case PixelFormat::BGR565:
+ const PixelFormatInfo& format_info = get_pixel_format_info(fb.format());
+
+ switch (format_info.type) {
+ case PixelColorType::RGB:
for (y = start_y; y < end_y; y++) {
for (x = 0; x < w; x++) {
RGB pixel = get_test_pattern_pixel(fb, x, y);
@@ -119,40 +117,46 @@
}
break;
- case PixelFormat::UYVY:
- case PixelFormat::YUYV:
- case PixelFormat::YVYU:
- case PixelFormat::VYUY:
- for (y = start_y; y < end_y; y++) {
- for (x = 0; x < w; x += 2) {
- RGB pixel1 = get_test_pattern_pixel(fb, x, y);
- RGB pixel2 = get_test_pattern_pixel(fb, x + 1, y);
- draw_yuv422_macropixel(fb, x, y, pixel1.yuv(yuvt), pixel2.yuv(yuvt));
+ case PixelColorType::YUV:
+ switch (format_info.num_planes) {
+ case 1:
+ for (y = start_y; y < end_y; y++) {
+ for (x = 0; x < w; x += 2) {
+ RGB pixel1 = get_test_pattern_pixel(fb, x, y);
+ RGB pixel2 = get_test_pattern_pixel(fb, x + 1, y);
+ draw_yuv422_macropixel(fb, x, y, pixel1.yuv(yuvt), pixel2.yuv(yuvt));
+ }
}
+ break;
+
+ case 2:
+ for (y = start_y; y < end_y; y += 2) {
+ for (x = 0; x < w; x += 2) {
+ RGB pixel00 = get_test_pattern_pixel(fb, x, y);
+ RGB pixel10 = get_test_pattern_pixel(fb, x + 1, y);
+ RGB pixel01 = get_test_pattern_pixel(fb, x, y + 1);
+ RGB pixel11 = get_test_pattern_pixel(fb, x + 1, y + 1);
+ draw_yuv420_macropixel(fb, x, y,
+ pixel00.yuv(yuvt), pixel10.yuv(yuvt),
+ pixel01.yuv(yuvt), pixel11.yuv(yuvt));
+ }
+ }
+ break;
+
+ default:
+ throw invalid_argument("unsupported number of pixel format planes");
}
+
break;
- case PixelFormat::NV12:
- case PixelFormat::NV21:
- for (y = start_y; y < end_y; y += 2) {
- for (x = 0; x < w; x += 2) {
- RGB pixel00 = get_test_pattern_pixel(fb, x, y);
- RGB pixel10 = get_test_pattern_pixel(fb, x + 1, y);
- RGB pixel01 = get_test_pattern_pixel(fb, x, y + 1);
- RGB pixel11 = get_test_pattern_pixel(fb, x + 1, y + 1);
- draw_yuv420_macropixel(fb, x, y,
- pixel00.yuv(yuvt), pixel10.yuv(yuvt),
- pixel01.yuv(yuvt), pixel11.yuv(yuvt));
- }
- }
- break;
default:
- throw std::invalid_argument("unknown pixelformat");
+ throw invalid_argument("unsupported pixel format");
}
}
static void draw_test_pattern_impl(IFramebuffer& fb, YUVType yuvt)
{
+#ifdef HAS_PTHREAD
if (fb.height() < 20) {
draw_test_pattern_part(fb, 0, fb.height(), yuvt);
return;
@@ -179,6 +183,9 @@
for (thread& t : workers)
t.join();
+#else
+ draw_test_pattern_part(fb, 0, fb.height(), yuvt);
+#endif
}
void draw_test_pattern(IFramebuffer &fb, YUVType yuvt)
diff --git a/kms++util/src/videodevice.cpp b/kms++util/src/videodevice.cpp
index efe1678..cc11357 100644
--- a/kms++util/src/videodevice.cpp
+++ b/kms++util/src/videodevice.cpp
@@ -96,6 +96,63 @@
}
}
+static void v4l2_get_selection(int fd, uint32_t& left, uint32_t& top, uint32_t& width, uint32_t& height, uint32_t buf_type)
+{
+ int r;
+ struct v4l2_selection selection;
+
+ if (buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+ buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ selection.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ selection.target = V4L2_SEL_TGT_CROP;
+ } else if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ selection.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ selection.target = V4L2_SEL_TGT_COMPOSE;
+ } else {
+ FAIL("buf_type (%d) is not valid\n", buf_type);
+ }
+
+ r = ioctl(fd, VIDIOC_G_SELECTION, &selection);
+ ASSERT(r == 0);
+
+ left = selection.r.left;
+ top = selection.r.top;
+ width = selection.r.width;
+ height = selection.r.height;
+}
+
+static void v4l2_set_selection(int fd, uint32_t& left, uint32_t& top, uint32_t& width, uint32_t& height, uint32_t buf_type)
+{
+ int r;
+ struct v4l2_selection selection;
+
+ if (buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+ buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ selection.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ selection.target = V4L2_SEL_TGT_CROP;
+ } else if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ selection.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ selection.target = V4L2_SEL_TGT_COMPOSE;
+ } else {
+ FAIL("buf_type (%d) is not valid\n", buf_type);
+ }
+
+ selection.r.left = left;
+ selection.r.top = top;
+ selection.r.width = width;
+ selection.r.height = height;
+
+ r = ioctl(fd, VIDIOC_S_SELECTION, &selection);
+ ASSERT(r == 0);
+
+ left = selection.r.left;
+ top = selection.r.top;
+ width = selection.r.width;
+ height = selection.r.height;
+}
+
static void v4l2_request_bufs(int fd, uint32_t queue_size, uint32_t buf_type)
{
v4l2_requestbuffers v4lreqbuf { };
@@ -414,6 +471,16 @@
v4l2_set_format(m_fd, fmt, width, height, get_buf_type(m_type));
}
+void VideoStreamer::get_selection(uint32_t& left, uint32_t& top, uint32_t& width, uint32_t& height)
+{
+ v4l2_get_selection(m_fd, left, top, width, height, get_buf_type(m_type));
+}
+
+void VideoStreamer::set_selection(uint32_t& left, uint32_t& top, uint32_t& width, uint32_t& height)
+{
+ v4l2_set_selection(m_fd, left, top, width, height, get_buf_type(m_type));
+}
+
void VideoStreamer::set_queue_size(uint32_t queue_size)
{
v4l2_request_bufs(m_fd, queue_size, get_buf_type(m_type));
diff --git a/py/pykms/__init__.py b/py/pykms/__init__.py
index 746c917..258b4e0 100644
--- a/py/pykms/__init__.py
+++ b/py/pykms/__init__.py
@@ -80,6 +80,64 @@
VBLANK = 0x01
FLIP_COMPLETE = 0x02
+#
+# AtomicReq API extensions
+#
+
+def __atomic_req_add_connector(req, conn, crtc):
+ req.add(conn, "CRTC_ID", crtc.id if crtc else 0)
+
+def __atomic_req_add_crtc(req, crtc, mode_blob):
+ if mode_blob:
+ req.add(crtc, {"ACTIVE": 1, "MODE_ID": mode_blob.id})
+ else:
+ req.add(crtc, {"ACTIVE": 0, "MODE_ID": 0})
+
+def __atomic_req_add_plane(req, plane, fb, crtc,
+ src=None, dst=None, zpos=None,
+ params={}):
+ if not src and fb:
+ src = (0, 0, fb.width, fb.height)
+
+ if not dst:
+ dst = src
+
+ m = {"FB_ID": fb.id if fb else 0,
+ "CRTC_ID": crtc.id if crtc else 0}
+
+ if src is not None:
+ src_x = int(round(src[0] * 65536))
+ src_y = int(round(src[1] * 65536))
+ src_w = int(round(src[2] * 65536))
+ src_h = int(round(src[3] * 65536))
+
+ m["SRC_X"] = src_x
+ m["SRC_Y"] = src_y
+ m["SRC_W"] = src_w
+ m["SRC_H"] = src_h
+
+ if dst is not None:
+ crtc_x = int(round(dst[0]))
+ crtc_y = int(round(dst[1]))
+ crtc_w = int(round(dst[2]))
+ crtc_h = int(round(dst[3]))
+
+ m["CRTC_X"] = crtc_x
+ m["CRTC_Y"] = crtc_y
+ m["CRTC_W"] = crtc_w
+ m["CRTC_H"] = crtc_h
+
+ if zpos is not None:
+ m["zpos"] = zpos
+
+ m.update(params)
+
+ req.add(plane, m)
+
+pykms.AtomicReq.add_connector = __atomic_req_add_connector
+pykms.AtomicReq.add_crtc = __atomic_req_add_crtc
+pykms.AtomicReq.add_plane = __atomic_req_add_plane
+
# struct drm_event {
# __u32 type;
# __u32 length;
diff --git a/py/pykms/pykmsbase.cpp b/py/pykms/pykmsbase.cpp
index 2c97bd7..668e6e3 100644
--- a/py/pykms/pykmsbase.cpp
+++ b/py/pykms/pykmsbase.cpp
@@ -21,6 +21,8 @@
{
py::class_<Card>(m, "Card")
.def(py::init<>())
+ .def(py::init<const string&>())
+ .def(py::init<const string&, uint32_t>())
.def_property_readonly("fd", &Card::fd)
.def_property_readonly("get_first_connected_connector", &Card::get_first_connected_connector)
@@ -45,6 +47,8 @@
.def_property_readonly("has_atomic", &Card::has_atomic)
.def("get_prop", (Property* (Card::*)(uint32_t) const)&Card::get_prop)
+
+ .def_property_readonly("version_name", &Card::version_name);
;
py::class_<DrmObject, unique_ptr<DrmObject, py::nodelete>>(m, "DrmObject")
diff --git a/py/pykms/pykmsutil.cpp b/py/pykms/pykmsutil.cpp
index 518d5ea..d5d7fde 100644
--- a/py/pykms/pykmsutil.cpp
+++ b/py/pykms/pykmsutil.cpp
@@ -57,6 +57,9 @@
m.def("draw_rect", [](Framebuffer& fb, uint32_t x, uint32_t y, uint32_t w, uint32_t h, RGB color) {
draw_rect(fb, x, y, w, h, color);
} );
+ m.def("draw_circle", [](Framebuffer& fb, int32_t xCenter, int32_t yCenter, int32_t radius, RGB color) {
+ draw_circle(fb, xCenter, yCenter, radius, color);
+ } );
m.def("draw_text", [](Framebuffer& fb, uint32_t x, uint32_t y, const string& str, RGB color) {
draw_text(fb, x, y, str, color); } );
}
diff --git a/py/pykms/pyvid.cpp b/py/pykms/pyvid.cpp
index 92006c4..8b0450a 100644
--- a/py/pykms/pyvid.cpp
+++ b/py/pykms/pyvid.cpp
@@ -30,6 +30,15 @@
.def("set_port", &VideoStreamer::set_port)
.def_property_readonly("formats", &VideoStreamer::get_formats)
.def("set_format", &VideoStreamer::set_format)
+ .def("get_selection", [](VideoStreamer *self) {
+ uint32_t left, top, width, height;
+ self->get_selection(left, top, width, height);
+ return make_tuple(left, top, width, height);
+ } )
+ .def("set_selection", [](VideoStreamer *self, uint32_t left, uint32_t top, uint32_t width, uint32_t height) {
+ self->set_selection(left, top, width, height);
+ return make_tuple(left, top, width, height);
+ } )
.def("set_queue_size", &VideoStreamer::set_queue_size)
.def("queue", &VideoStreamer::queue)
.def("dequeue", &VideoStreamer::dequeue)
diff --git a/py/tests/alpha-test.py b/py/tests/alpha-test.py
index 9ae1539..e329ce4 100755
--- a/py/tests/alpha-test.py
+++ b/py/tests/alpha-test.py
@@ -54,7 +54,7 @@
"SRC_H": fb.height << 16,
"CRTC_W": fb.width,
"CRTC_H": fb.height,
- "zorder": i,
+ "zpos": i,
})
time.sleep(1)
diff --git a/py/tests/big_fb.py b/py/tests/big_fb.py
index 54de685..dc08bd2 100755
--- a/py/tests/big_fb.py
+++ b/py/tests/big_fb.py
@@ -89,7 +89,7 @@
'CRTC_Y': 0,
'CRTC_W': mode.hdisplay,
'CRTC_H': mode.vdisplay,
- 'zorder': 0})
+ 'zpos': 0})
req.commit_sync(allow_modeset = True)
@@ -187,7 +187,7 @@
'CRTC_Y': 0,
'CRTC_W': mode.hdisplay,
'CRTC_H': mode.vdisplay,
- 'zorder': 0})
+ 'zpos': 0})
screen_offset += mode.hdisplay
@@ -219,7 +219,7 @@
'CRTC_Y': 0,
'CRTC_W': mode.hdisplay,
'CRTC_H': mode.vdisplay,
- 'zorder': 0})
+ 'zpos': 0})
screen_offset += mode.hdisplay
diff --git a/py/tests/global_alpha_test.py b/py/tests/global_alpha_test.py
new file mode 100755
index 0000000..6981b72
--- /dev/null
+++ b/py/tests/global_alpha_test.py
@@ -0,0 +1,46 @@
+#!/usr/bin/python3
+
+import pykms
+import time
+
+card = pykms.Card()
+res = pykms.ResourceManager(card)
+conn = res.reserve_connector("")
+crtc = res.reserve_crtc(conn)
+mode = conn.get_default_mode()
+modeb = mode.to_blob(card)
+format = pykms.PixelFormat.ARGB8888
+plane1 = res.reserve_generic_plane(crtc, format)
+plane2 = res.reserve_generic_plane(crtc, format)
+
+print("Got plane1 %d %d plane2 %d %d" %
+ (plane1.idx, plane1.id, plane2.idx, plane2.id))
+
+fb1 = pykms.DumbFramebuffer(card, mode.hdisplay, mode.vdisplay, format);
+pykms.draw_test_pattern(fb1);
+
+fb2 = pykms.DumbFramebuffer(card, mode.hdisplay >> 1, mode.vdisplay >> 1, format);
+pykms.draw_test_pattern(fb2);
+
+alpha = 0
+
+req = pykms.AtomicReq(card)
+req.add(conn, "CRTC_ID", crtc.id)
+req.add(crtc, {"ACTIVE": 1,
+ "MODE_ID": modeb.id})
+req.add_plane(plane1, fb1, crtc)
+req.add_plane(plane2, fb2, crtc)
+
+r = req.commit_sync(allow_modeset = True)
+assert r == 0, "Initial commit failed: %d" % r
+
+while alpha <= 0xFFFF:
+ print("alpha %d" % (alpha >> 8))
+ req = pykms.AtomicReq(card)
+ req.add(plane2, {"alpha": alpha })
+ r = req.commit_sync()
+ assert r == 0, "alpha change commit failed: %d" % r
+ alpha = alpha + 0xFF
+ time.sleep(0.1)
+
+input("press enter exit\n")
diff --git a/py/tests/plane_csc.py b/py/tests/plane_csc.py
index be92c00..5e6c6b5 100755
--- a/py/tests/plane_csc.py
+++ b/py/tests/plane_csc.py
@@ -4,12 +4,11 @@
card = pykms.Card()
res = pykms.ResourceManager(card)
-conn = res.reserve_connector("HDMI")
+conn = res.reserve_connector("")
crtc = res.reserve_crtc(conn)
mode = conn.get_default_mode()
modeb = mode.to_blob(card)
plane = res.reserve_generic_plane(crtc, pykms.PixelFormat.UYVY)
-#plane = res.reserve_generic_plane(crtc, pykms.PixelFormat.Undefined)
print("Got plane %d %d" % (plane.idx, plane.id))
@@ -27,17 +26,7 @@
input("Press enter to enable plane idx %d at %s" % (plane.idx, conn.fullname))
req = pykms.AtomicReq(card)
-req.add(plane, {"FB_ID": fb.id,
- "CRTC_ID": crtc.id,
- "SRC_X": 0 << 16,
- "SRC_Y": 0 << 16,
- "SRC_W": fb.width << 16,
- "SRC_H": fb.height << 16,
- "CRTC_X": 0,
- "CRTC_Y": 0,
- "CRTC_W": fb.width,
- "CRTC_H": fb.height,
- "zorder": 0})
+req.add_plane(plane, fb, crtc)
r = req.commit_sync()
print("Plane enable request returned %d\n" % r)
diff --git a/py/tests/plane_hog.py b/py/tests/plane_hog.py
index 5bdc937..906c758 100755
--- a/py/tests/plane_hog.py
+++ b/py/tests/plane_hog.py
@@ -77,7 +77,7 @@
"CRTC_Y": y,
"CRTC_W": fb.width,
"CRTC_H": fb.height,
- "zorder": z})
+ "zpos": z})
r = req.commit_sync()
print("Plane enable request returned %d\n" % r)
@@ -125,7 +125,7 @@
"CRTC_Y": y,
"CRTC_W": fb.width,
"CRTC_H": fb.height,
- "zorder": z})
+ "zpos": z})
r = req.commit_sync(allow_modeset = True)
print("Plane enable request returned %d\n" % r)
diff --git a/py/tests/plane_move.py b/py/tests/plane_move.py
new file mode 100755
index 0000000..2f9dee5
--- /dev/null
+++ b/py/tests/plane_move.py
@@ -0,0 +1,128 @@
+#!/usr/bin/python3
+
+import pykms
+import random
+import time
+import sys
+import select
+import selectors
+
+if len(sys.argv) != 3:
+ print('Usage: plane_move.py <connector0> <connector1>')
+ sys.exit()
+
+card = pykms.Card()
+
+if not card.has_atomic:
+ print('Atomic modesetting is not supported')
+ sys.exit(-1)
+
+res = pykms.ResourceManager(card)
+
+conn_list = []
+crtc_list = []
+mode_list = []
+rootplane_list = []
+fb_list = []
+colors = []
+
+src_w = 300
+src_h = 300
+
+for i in range(2):
+ conn = res.reserve_connector(sys.argv[i + 1])
+ if conn is None:
+ print('Invalid connector: {}'.format(sys.argv[i + 1]))
+ sys.exit(-1)
+
+ if conn.connected() == True:
+ conn_list.append(conn)
+ else:
+ print('connector: {} is not connected'.format(sys.argv[i + 1]))
+ sys.exit(-1)
+
+ crtc = res.reserve_crtc(conn)
+ crtc_list.append(crtc)
+
+ mode = conn.get_default_mode()
+ mode_list.append(mode)
+
+ fb_tmp = pykms.DumbFramebuffer(card, src_w, src_h, 'XR24');
+ fb_list.append(fb_tmp)
+
+ rootplane = res.reserve_primary_plane(crtc, pykms.PixelFormat.XRGB8888)
+ rootplane_list.append(rootplane)
+
+card.disable_planes()
+
+print('Using the following connectors:')
+for i in range(2):
+ print(' {}: {} ({}x{})'.format(conn_list[i].idx, conn_list[i].fullname,
+ mode_list[i].hdisplay, mode_list[i].vdisplay))
+
+colors.append(pykms.red)
+colors.append(pykms.green)
+
+for i in range(2):
+ pykms.draw_rect(fb_list[i], 0, 0, src_w, src_h, colors[i])
+
+for i in range(2):
+ req = pykms.AtomicReq(card)
+ modeb = mode_list[i].to_blob(card)
+ req.add(conn_list[i], 'CRTC_ID', crtc_list[i].id)
+ req.add(crtc_list[i], {'ACTIVE': 1,
+ 'MODE_ID': modeb.id})
+ req.add(rootplane_list[i], {'FB_ID': fb_list[i].id,
+ 'CRTC_ID': crtc_list[i].id,
+ 'SRC_W': src_w << 16,
+ 'SRC_H': src_h << 16,
+ 'CRTC_W': src_w,
+ 'CRTC_H': src_h})
+
+ req.commit_sync(allow_modeset = True)
+
+print('\nRed box on {}, Green box on {}.'.format(conn_list[0].fullname,
+ conn_list[1].fullname))
+input('ENTER to continue\n')
+
+# FIXME: it should be possible to move plane without disabling it, but the
+# omapdrm driver does not supports it at the moment.
+req = pykms.AtomicReq(card)
+req.add(rootplane_list[0], {"FB_ID": 0,
+ "CRTC_ID": 0})
+req.commit_sync(allow_modeset = True)
+
+req = pykms.AtomicReq(card)
+req.add(rootplane_list[0], {'FB_ID': fb_list[0].id,
+ 'CRTC_ID': crtc_list[1].id,
+ 'SRC_W': src_w << 16,
+ 'SRC_H': src_h << 16,
+ 'CRTC_X': 150,
+ 'CRTC_Y': 150,
+ 'CRTC_W': src_w,
+ 'CRTC_H': src_h})
+req.commit_sync(allow_modeset = True)
+
+print('The red box from {} is moved underneath the green box on {}.'.format(
+ conn_list[0].fullname, conn_list[1].fullname))
+input('ENTER to continue\n')
+
+# FIXME: it should be possible to move plane without disabling it, but the
+# omapdrm driver does not supports it at the moment.
+req = pykms.AtomicReq(card)
+req.add(rootplane_list[1], {"FB_ID": 0,
+ "CRTC_ID": 0})
+req.commit_sync(allow_modeset = True)
+
+req = pykms.AtomicReq(card)
+req.add(rootplane_list[1], {'FB_ID': fb_list[1].id,
+ 'CRTC_ID': crtc_list[0].id,
+ 'SRC_W': src_w << 16,
+ 'SRC_H': src_h << 16,
+ 'CRTC_W': src_w,
+ 'CRTC_H': src_h})
+req.commit_sync(allow_modeset = True)
+
+print('Green box on {}, Red box on {}.'.format(conn_list[0].fullname,
+ conn_list[1].fullname))
+input('ENTER to exit\n')
diff --git a/py/tests/rottest.py b/py/tests/rottest.py
index 8988134..c568e17 100755
--- a/py/tests/rottest.py
+++ b/py/tests/rottest.py
@@ -39,7 +39,7 @@
# "CRTC_Y": 0,
# "CRTC_W": mode.hdisplay,
# "CRTC_H": mode.vdisplay,
-# "zorder": 0})
+# "zpos": 0})
req.commit_sync(allow_modeset = True)
@@ -86,7 +86,7 @@
"CRTC_W": crtc_w,
"CRTC_H": crtc_h,
"rotation": rot,
- "zorder": 2})
+ "zpos": 2})
req.commit_sync(allow_modeset = True)
diff --git a/py/tests/scale.py b/py/tests/scale.py
index 0b97051..0cf71dd 100755
--- a/py/tests/scale.py
+++ b/py/tests/scale.py
@@ -3,50 +3,80 @@
import pykms
import time
import random
+import argparse
+
+def plane_commit(card, crtc, plane, fb, x, y, w, h) :
+ req = pykms.AtomicReq(card)
+ req.add_plane(plane, fb, crtc, None, (x, y, w, h))
+ r = req.commit_sync()
+ assert r == 0, "Plane commit failed: %d" % r
+
+
+parser = argparse.ArgumentParser(description='Simple scaling stress test.')
+parser.add_argument('--plane', '-p', dest='plane', default="",
+ required=False, help='plane number to use')
+parser.add_argument('--connector', '-c', dest='connector', default="",
+ required=False, help='connector to output')
+
+args = parser.parse_args()
card = pykms.Card()
res = pykms.ResourceManager(card)
-conn = res.reserve_connector("hdmi")
+conn = res.reserve_connector(args.connector)
crtc = res.reserve_crtc(conn)
-plane = res.reserve_overlay_plane(crtc)
+format = pykms.PixelFormat.NV12
+
+if args.plane == "":
+ plane = res.reserve_generic_plane(crtc, format)
+else:
+ plane = card.planes[int(args.plane)]
mode = conn.get_default_mode()
-#mode = conn.get_mode(1920, 1080, 60, False)
-
-# Blank framefuffer for primary plane
-fb0 = pykms.DumbFramebuffer(card, mode.hdisplay, mode.vdisplay, "AR24");
-
-crtc.set_mode(conn, fb0, 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})
+r = req.commit_sync(allow_modeset = True)
+assert r == 0, "Initial commit failed: %d" % r
# Initialize framebuffer for the scaled plane
fbX = 1920
fbY = 1080
-fb = pykms.DumbFramebuffer(card, fbX, fbY, "RG16");
+fb = pykms.DumbFramebuffer(card, fbX, fbY, format);
pykms.draw_test_pattern(fb);
-# Plane's scaled size and size increments
-W = 72
-H = 54
-Winc = 1
-Hinc = 1
+# max downscale.
+# The values bellow are for DSS5. For DSS7 use 64 for both.
+max_downscale_x=5
+max_downscale_y=8
-# Plane's position and position increments
+# Plane's initial scaled size
+W = 640
+H = 480
+
+# Plane's initial position
X = 0
Y = 0
+
+# initialize increments
+Winc = 1
+Hinc = 1
Xinc = 1
Yinc = 1
+
while True:
print("+%d+%d %dx%d" % (X, Y, W, H))
- crtc.set_plane(plane, fb, X, Y, W, H, 0, 0, fbX, fbY)
+ plane_commit(card, crtc, plane, fb, X, Y, W, H)
W = W + Winc
H = H + Hinc
if (Winc == 1 and W >= mode.hdisplay - X):
Winc = -1
- if (Winc == -1 and W <= fbX/32):
+ if (Winc == -1 and W <= fbX/max_downscale_x):
Winc = 1
if (Hinc == 1 and H >= mode.vdisplay - Y):
Hinc = -1
- if (Hinc == -1 and H <= fbY/32):
+ if (Hinc == -1 and H <= fbY/max_downscale_y):
Hinc = 1
X = X + Xinc
Y = Y + Yinc
diff --git a/py/tests/sync.py b/py/tests/sync.py
index e394c8d..935d86e 100755
--- a/py/tests/sync.py
+++ b/py/tests/sync.py
@@ -178,7 +178,7 @@
fb = flip_handler.fb1
pykms.draw_color_bar(fb, fb.width - bar_width - bar_speed, bar_speed, bar_width)
- mode_blob = mode.blob(card)
+ mode_blob = mode.to_blob(card)
req = pykms.AtomicReq(card)
req.add(conn, 'CRTC_ID', crtc.id)
@@ -195,7 +195,7 @@
'CRTC_W': fb.width,
'CRTC_H': fb.height,
})
- ret = req.commit(flip_handler, allow_modeset = True)
+ ret = req.commit(allow_modeset = True)
if ret < 0:
raise RuntimeError('Atomic mode set failed with %d' % ret)
diff --git a/py/tests/test.py b/py/tests/test.py
index b7bf6bd..83cf16a 100755
--- a/py/tests/test.py
+++ b/py/tests/test.py
@@ -2,36 +2,32 @@
import sys
import pykms
+import argparse
-# draw test pattern via dmabuf?
-dmabuf = False
+parser = argparse.ArgumentParser()
+parser.add_argument("-c", "--connector", default="")
+parser.add_argument("--dmabuf", action="store_true", help="use dmabuf")
+parser.add_argument("--omap", action="store_true", help="use omapcard")
+args = parser.parse_args()
-# Use omap?
-omap = False
-
-if omap:
+if args.omap:
card = pykms.OmapCard()
else:
card = pykms.Card()
-if len(sys.argv) > 1:
- conn_name = sys.argv[1]
-else:
- conn_name = ""
-
res = pykms.ResourceManager(card)
-conn = res.reserve_connector(conn_name)
+conn = res.reserve_connector(args.connector)
crtc = res.reserve_crtc(conn)
plane = res.reserve_generic_plane(crtc)
mode = conn.get_default_mode()
modeb = mode.to_blob(card)
-if omap:
+if args.omap:
origfb = pykms.OmapFramebuffer(card, mode.hdisplay, mode.vdisplay, "XR24");
else:
origfb = pykms.DumbFramebuffer(card, mode.hdisplay, mode.vdisplay, "XR24");
-if dmabuf:
+if args.dmabuf:
fb = pykms.ExtFramebuffer(card, origfb.width, origfb.height, origfb.format,
[origfb.fd(0)], [origfb.stride(0)], [origfb.offset(0)])
else:
@@ -43,22 +39,9 @@
req = pykms.AtomicReq(card)
-req.add(conn, "CRTC_ID", crtc.id)
-
-req.add(crtc, {"ACTIVE": 1,
- "MODE_ID": modeb.id})
-
-req.add(plane, {"FB_ID": fb.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.add_connector(conn, crtc)
+req.add_crtc(crtc, modeb)
+req.add_plane(plane, fb, crtc, dst=(0, 0, mode.hdisplay, mode.vdisplay))
req.commit_sync(allow_modeset = True)
diff --git a/py/tests/trans-test.py b/py/tests/trans-test.py
index 8b8e6c5..3e7b9e3 100755
--- a/py/tests/trans-test.py
+++ b/py/tests/trans-test.py
@@ -2,14 +2,36 @@
import pykms
import time
+import sys
+import argparse
-# This hack makes drm initialize the fbcon, setting up the default connector
-card = pykms.Card()
-card = 0
+tests = {
+ 1: "test_am5_trans_dest",
+ 2: "test_am5_trans_src",
+ 3: "test_am4_normal_trans_dst",
+ 4: "test_am4_normal_trans_src",
+ 5: "test_am4_alpha_trans_src",
+}
+
+parser = argparse.ArgumentParser()
+parser.add_argument("-c", "--connector", default="")
+parser.add_argument("test", type=int, help="test number 1-" + str(len(tests)))
+args = parser.parse_args()
+
+#if len(sys.argv) != 2:
+# print("Usage: {} <test-number>".format(sys.argv[0]))
+# print(" 1 - test_am5_trans_dest()")
+# print(" 2 - test_am5_trans_src()")
+# print(" 3 - test_am4_normal_trans_dst()")
+# print(" 4 - test_am4_normal_trans_src()")
+# print(" 5 - test_am4_alpha_trans_src()")
+# exit(0)
+
+TEST = args.test
card = pykms.Card()
res = pykms.ResourceManager(card)
-conn = res.reserve_connector()
+conn = res.reserve_connector(args.connector)
crtc = res.reserve_crtc(conn)
mode = conn.get_default_mode()
@@ -26,19 +48,33 @@
fbs=[]
+# See Figure 11-78. DISPC Destination Transparency Color Key Example
def test_am5_trans_dest():
fbs.append(pykms.DumbFramebuffer(card, w, h, "XR24"))
fbs.append(pykms.DumbFramebuffer(card, w, h, "XR24"))
fb = fbs[0]
+ stepX = fb.width // 7
+ stepY = fb.height // 5;
+
pykms.draw_rect(fb, 0, 0, fb.width, fb.height, pykms.purple)
- pykms.draw_rect(fb, 100, 100, 100, 200, pykms.green)
- pykms.draw_rect(fb, 300, 100, 100, 200, pykms.red)
- pykms.draw_rect(fb, 500, 100, 100, 200, pykms.white)
+ pykms.draw_rect(fb, stepX, stepY,
+ stepX, fb.height - (stepY * 2),
+ pykms.green)
+ pykms.draw_rect(fb, stepX * 3, stepY,
+ stepX, fb.height - (stepY * 2),
+ pykms.red)
+ pykms.draw_rect(fb, stepX * 5, stepY,
+ stepX, fb.height - (stepY * 2),
+ pykms.white)
fb = fbs[1]
- pykms.draw_rect(fb, 0, 0, fb.width, fb.height, pykms.cyan)
- pykms.draw_rect(fb, 250, 100, 200, 200, pykms.yellow)
+ pykms.draw_rect(fb, 0, 0,
+ fb.width, fb.height,
+ pykms.cyan)
+ pykms.draw_circle(fb, (stepX * 3) + (stepX // 2), fb.height // 2,
+ (fb.height // 2) - stepY,
+ pykms.yellow)
crtc.set_props({
"trans-key-mode": 1,
@@ -47,37 +83,65 @@
"alpha_blender": 0,
})
- plane = 0
+ print("Purple bg. Green, red, white boxes.")
- for i in range(0,2):
- print("set crtc {}, plane {}, fb {}".format(crtc.id, planes[i].id, fbs[i].id))
+ plane = planes[0]
+ fb = fbs[0]
+ z = 0
- plane = planes[i]
- fb = fbs[i]
- plane.set_props({
- "FB_ID": fb.id,
- "CRTC_ID": crtc.id,
- "SRC_W": fb.width << 16,
- "SRC_H": fb.height << 16,
- "CRTC_W": fb.width,
- "CRTC_H": fb.height,
- "zorder": i,
- })
+ plane.set_props({
+ "FB_ID": fb.id,
+ "CRTC_ID": crtc.id,
+ "SRC_W": fb.width << 16,
+ "SRC_H": fb.height << 16,
+ "CRTC_W": fb.width,
+ "CRTC_H": fb.height,
+ "zpos": z,
+ })
- time.sleep(1)
+ input("press enter\n")
+ print("Cyan bg. Green, red, white boxes. Yellow circle behind the red box.")
+
+ plane = planes[1]
+ fb = fbs[1]
+ z = 1
+
+ plane.set_props({
+ "FB_ID": fb.id,
+ "CRTC_ID": crtc.id,
+ "SRC_W": fb.width << 16,
+ "SRC_H": fb.height << 16,
+ "CRTC_W": fb.width,
+ "CRTC_H": fb.height,
+ "zpos": z,
+ })
+
+ input("press enter\n")
+
+# See Figure 11-77. DISPC Source Transparency Color Key Example
def test_am5_trans_src():
fbs.append(pykms.DumbFramebuffer(card, w, h, "XR24"))
fbs.append(pykms.DumbFramebuffer(card, w, h, "XR24"))
fb = fbs[0]
+ halfX = fb.width // 2
+ stepX = (fb.width // 2) // 5;
+ stepY = fb.height // 5;
+
pykms.draw_rect(fb, 0, 0, fb.width, fb.height, pykms.white)
- pykms.draw_rect(fb, 200, 200, 100, 100, pykms.red)
- pykms.draw_rect(fb, fb.width - 300, 200, 100, 100, pykms.green)
+ pykms.draw_rect(fb, stepX * 2, stepY * 2,
+ halfX - (stepX * 4), fb.height - (stepY * 4),
+ pykms.red)
+ pykms.draw_rect(fb, halfX + stepX * 2, stepY * 2,
+ halfX - (stepX * 4), fb.height - (stepY * 4),
+ pykms.green)
fb = fbs[1]
pykms.draw_rect(fb, 0, 0, fb.width, fb.height, pykms.cyan)
- pykms.draw_rect(fb, 100, 100, fb.width - 200, fb.height - 200, pykms.purple)
+ pykms.draw_rect(fb, stepX, stepY,
+ fb.width - (stepX * 2), fb.height - (stepY * 2),
+ pykms.purple)
crtc.set_props({
"trans-key-mode": 2,
@@ -86,41 +150,68 @@
"alpha_blender": 0,
})
- plane = 0
+ print("White bg. Red and green boxes.")
- for i in range(0,2):
- print("set crtc {}, plane {}, fb {}".format(crtc.id, planes[i].id, fbs[i].id))
+ plane = planes[0]
+ fb = fbs[0]
+ z = 0
- plane = planes[i]
- fb = fbs[i]
- plane.set_props({
- "FB_ID": fb.id,
- "CRTC_ID": crtc.id,
- "SRC_W": fb.width << 16,
- "SRC_H": fb.height << 16,
- "CRTC_W": fb.width,
- "CRTC_H": fb.height,
- "zorder": 3 if i == 1 else 0,
- })
+ plane.set_props({
+ "FB_ID": fb.id,
+ "CRTC_ID": crtc.id,
+ "SRC_W": fb.width << 16,
+ "SRC_H": fb.height << 16,
+ "CRTC_W": fb.width,
+ "CRTC_H": fb.height,
+ "zpos": z,
+ })
- time.sleep(1)
+ input("press enter\n")
+
+ print("Cyan bg. Big white box, containing red and green boxes.")
+
+ plane = planes[1]
+ fb = fbs[1]
+ z = 3
+
+ plane.set_props({
+ "FB_ID": fb.id,
+ "CRTC_ID": crtc.id,
+ "SRC_W": fb.width << 16,
+ "SRC_H": fb.height << 16,
+ "CRTC_W": fb.width,
+ "CRTC_H": fb.height,
+ "zpos": z,
+ })
+
+ input("press enter\n")
def test_am4_normal_trans_dst():
fbs.append(pykms.DumbFramebuffer(card, w, h, "XR24"))
- fbs.append(pykms.DumbFramebuffer(card, w * 2 // 3, h, "XR24"))
- fbs.append(pykms.DumbFramebuffer(card, w * 2 // 3, h, "XR24"))
+ fbs.append(pykms.DumbFramebuffer(card, w, h, "XR24"))
fb = fbs[0]
- pykms.draw_rect(fb, 0, 0, w, h, pykms.purple)
- pykms.draw_rect(fb, 100, 50, 50, 200, pykms.green)
- pykms.draw_rect(fb, 200, 50, 50, 200, pykms.red)
- pykms.draw_rect(fb, 300, 50, 50, 200, pykms.white)
+ stepX = fb.width // 7
+ stepY = fb.height // 5;
+
+ pykms.draw_rect(fb, 0, 0, fb.width, fb.height, pykms.purple)
+ pykms.draw_rect(fb, stepX, stepY,
+ stepX, fb.height - (stepY * 2),
+ pykms.green)
+ pykms.draw_rect(fb, stepX * 3, stepY,
+ stepX, fb.height - (stepY * 2),
+ pykms.red)
+ pykms.draw_rect(fb, stepX * 5, stepY,
+ stepX, fb.height - (stepY * 2),
+ pykms.white)
fb = fbs[1]
- pykms.draw_rect(fb, 0, 0, fb.width, fb.height, pykms.blue)
-
- fb = fbs[2]
- pykms.draw_rect(fb, 0, 0, fb.width, fb.height, pykms.cyan)
+ pykms.draw_rect(fb, 0, 0,
+ fb.width, fb.height,
+ pykms.cyan)
+ pykms.draw_circle(fb, (stepX * 3) + (stepX // 2), fb.height // 2,
+ (fb.height // 2) - stepY,
+ pykms.yellow)
crtc.set_props({
"trans-key-mode": 1,
@@ -129,70 +220,64 @@
"alpha_blender": 0,
})
- time.sleep(1)
+ print("Purple bg. Green, red, white boxes.")
plane = planes[0]
fb = fbs[0]
+ z = 0
+
plane.set_props({
"FB_ID": fb.id,
"CRTC_ID": crtc.id,
"SRC_W": fb.width << 16,
"SRC_H": fb.height << 16,
- "CRTC_W": w,
- "CRTC_H": h,
+ "CRTC_W": fb.width,
+ "CRTC_H": fb.height,
+ "zpos": z,
})
- time.sleep(1)
+ input("press enter\n")
+
+ print("Cyan bg. Green, red, white boxes. Yellow circle behind the red box.")
plane = planes[1]
fb = fbs[1]
+ z = 1
+
plane.set_props({
"FB_ID": fb.id,
"CRTC_ID": crtc.id,
- "SRC_X": 0 << 16,
- "SRC_Y": 0 << 16,
"SRC_W": fb.width << 16,
"SRC_H": fb.height << 16,
- "CRTC_X": 0,
- "CRTC_Y": 0,
"CRTC_W": fb.width,
"CRTC_H": fb.height,
+ "zpos": z,
})
- time.sleep(1)
-
- plane = planes[2]
- fb = fbs[2]
- plane.set_props({
- "FB_ID": fb.id,
- "CRTC_ID": crtc.id,
- "SRC_X": 0 << 16,
- "SRC_Y": 0 << 16,
- "SRC_W": fb.width << 16,
- "SRC_H": fb.height << 16,
- "CRTC_X": w // 3,
- "CRTC_Y": 0,
- "CRTC_W": fb.width,
- "CRTC_H": fb.height,
- })
+ input("press enter\n")
def test_am4_normal_trans_src():
fbs.append(pykms.DumbFramebuffer(card, w, h, "XR24"))
- fbs.append(pykms.DumbFramebuffer(card, w // 2, h, "XR24"))
- fbs.append(pykms.DumbFramebuffer(card, w // 2, h, "XR24"))
+ fbs.append(pykms.DumbFramebuffer(card, w, h, "XR24"))
fb = fbs[0]
- pykms.draw_rect(fb, 0, 0, w, h, pykms.RGB(128, 255, 255))
- pykms.draw_rect(fb, 200, 100, 50, 200, pykms.red)
- pykms.draw_rect(fb, w - 200 - 50, 100, 50, 200, pykms.green)
+ halfX = fb.width // 2
+ stepX = (fb.width // 2) // 5;
+ stepY = fb.height // 5;
+
+ pykms.draw_rect(fb, 0, 0, fb.width, fb.height, pykms.white)
+ pykms.draw_rect(fb, stepX * 2, stepY * 2,
+ halfX - (stepX * 4), fb.height - (stepY * 4),
+ pykms.red)
+ pykms.draw_rect(fb, halfX + stepX * 2, stepY * 2,
+ halfX - (stepX * 4), fb.height - (stepY * 4),
+ pykms.green)
fb = fbs[1]
- pykms.draw_rect(fb, 0, 0, fb.width, fb.height, pykms.blue)
- pykms.draw_rect(fb, 100, 100, fb.width - 200, fb.height - 200, pykms.purple)
-
- fb = fbs[2]
pykms.draw_rect(fb, 0, 0, fb.width, fb.height, pykms.cyan)
- pykms.draw_rect(fb, 100, 100, fb.width - 200, fb.height - 200, pykms.purple)
+ pykms.draw_rect(fb, stepX, stepY,
+ fb.width - (stepX * 2), fb.height - (stepY * 2),
+ pykms.purple)
crtc.set_props({
"trans-key-mode": 2,
@@ -201,52 +286,41 @@
"alpha_blender": 0,
})
- time.sleep(1)
+ print("White bg. Red and green boxes.")
plane = planes[0]
fb = fbs[0]
+ z = 0
+
plane.set_props({
"FB_ID": fb.id,
"CRTC_ID": crtc.id,
"SRC_W": fb.width << 16,
"SRC_H": fb.height << 16,
- "CRTC_W": w,
- "CRTC_H": h,
+ "CRTC_W": fb.width,
+ "CRTC_H": fb.height,
+ "zpos": z,
})
- time.sleep(1)
+ input("press enter\n")
+
+ print("Cyan bg. Big white box, containing red and green boxes.")
plane = planes[1]
fb = fbs[1]
+ z = 2
+
plane.set_props({
"FB_ID": fb.id,
"CRTC_ID": crtc.id,
- "SRC_X": 0 << 16,
- "SRC_Y": 0 << 16,
"SRC_W": fb.width << 16,
"SRC_H": fb.height << 16,
- "CRTC_X": 0,
- "CRTC_Y": 0,
"CRTC_W": fb.width,
"CRTC_H": fb.height,
+ "zpos": z,
})
- time.sleep(1)
-
- plane = planes[2]
- fb = fbs[2]
- plane.set_props({
- "FB_ID": fb.id,
- "CRTC_ID": crtc.id,
- "SRC_X": 0 << 16,
- "SRC_Y": 0 << 16,
- "SRC_W": fb.width << 16,
- "SRC_H": fb.height << 16,
- "CRTC_X": w - fb.width,
- "CRTC_Y": 0,
- "CRTC_W": fb.width,
- "CRTC_H": fb.height,
- })
+ input("press enter\n")
def test_am4_alpha_trans_src():
fbs.append(pykms.DumbFramebuffer(card, w, h, "XR24"))
@@ -254,26 +328,39 @@
fbs.append(pykms.DumbFramebuffer(card, w // 2, h, "XR24"))
fb = fbs[0]
+ halfX = fb.width // 2
+ stepX = (fb.width // 2) // 5;
+ stepY = fb.height // 5;
+
pykms.draw_rect(fb, 0, 0, w, h, pykms.purple)
- pykms.draw_rect(fb, 200, 100, 50, 200, pykms.red)
- pykms.draw_rect(fb, w - 200 - 50, 100, 50, 200, pykms.green)
+ pykms.draw_rect(fb, stepX * 2, stepY * 2,
+ halfX - (stepX * 4), fb.height - (stepY * 4),
+ pykms.red)
+ pykms.draw_rect(fb, halfX + stepX * 2, stepY * 2,
+ halfX - (stepX * 4), fb.height - (stepY * 4),
+ pykms.green)
fb = fbs[1]
pykms.draw_rect(fb, 0, 0, fb.width, fb.height, pykms.blue)
- pykms.draw_rect(fb, 100, 100, fb.width - 200, fb.height - 200, pykms.purple)
+ pykms.draw_rect(fb, stepX, stepY,
+ fb.width - (stepX * 2), fb.height - (stepY * 2),
+ pykms.purple)
fb = fbs[2]
pykms.draw_rect(fb, 0, 0, fb.width, fb.height, pykms.cyan)
- pykms.draw_rect(fb, 100, 100, fb.width - 200, fb.height - 200, pykms.purple)
+ pykms.draw_rect(fb, stepX, stepY,
+ fb.width - (stepX * 2), fb.height - (stepY * 2),
+ pykms.purple)
crtc.set_props({
"trans-key-mode": 1,
"trans-key": pykms.purple.rgb888,
- "background": 0,
+ "background": 0x666666,
"alpha_blender": 1,
})
- time.sleep(1)
+ print("grey background")
+ input("press enter\n")
plane = planes[0]
fb = fbs[0]
@@ -286,7 +373,8 @@
"CRTC_H": h,
})
- time.sleep(1)
+ print("grey background, red and green boxes")
+ input("press enter\n")
plane = planes[1]
fb = fbs[1]
@@ -303,7 +391,8 @@
"CRTC_H": fb.height,
})
- time.sleep(1)
+ print("left side: blue bg, purple box, red box inside purple. right side: unchanged")
+ input("press enter\n")
plane = planes[2]
fb = fbs[2]
@@ -320,12 +409,8 @@
"CRTC_H": fb.height,
})
+ print("left side: unchanged. right side: cyan bg, purple box, green box inside purple.")
+ input("press enter\n")
-
-#test_am5_trans_dest()
-test_am5_trans_src()
-#test_am4_normal_trans_dst()
-#test_am4_normal_trans_src()
-#test_am4_alpha_trans_src()
-
-input("press enter to exit\n")
+print(tests[args.test])
+locals()[tests[args.test]]()
diff --git a/py/tests/wb-m2m-crop.py b/py/tests/wb-m2m-crop.py
new file mode 100755
index 0000000..6c4225d
--- /dev/null
+++ b/py/tests/wb-m2m-crop.py
@@ -0,0 +1,123 @@
+#!/usr/bin/python3
+
+import sys
+import selectors
+import pykms
+import argparse
+import time
+
+iw = 640
+ih = 480
+ifmt = pykms.PixelFormat.XRGB8888
+
+ow = 640
+oh = 480
+ofmt = pykms.PixelFormat.XRGB8888
+
+card = pykms.Card()
+res = pykms.ResourceManager(card)
+conn = res.reserve_connector()
+crtc = res.reserve_crtc(conn)
+plane1 = res.reserve_overlay_plane(crtc, ifmt)
+plane2 = res.reserve_overlay_plane(crtc, ofmt)
+
+print("{}, {}".format(plane1.id, plane2.id))
+
+mode = conn.get_default_mode()
+modeb = mode.to_blob(card)
+
+card.disable_planes()
+
+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 = 4
+
+src_fbs = []
+dst_fbs = []
+
+for i in range(NUM_BUFS):
+ fb = pykms.DumbFramebuffer(card, iw, ih, ifmt)
+ pykms.draw_test_pattern(fb);
+ pykms.draw_text(fb, iw // 2, 2, str(i), pykms.white);
+ src_fbs.append(fb)
+
+ fb = pykms.DumbFramebuffer(card, ow, oh, ofmt)
+ dst_fbs.append(fb)
+
+# put the planes on the screen, so that WB doesn't take them
+req = pykms.AtomicReq(card)
+req.add_plane(plane1, src_fbs[0], crtc, dst=(0, 0, 400, 480))
+req.add_plane(plane2, dst_fbs[1], crtc, dst=(400, 0, 400, 480))
+r = req.commit_sync(allow_modeset = True)
+assert r == 0
+
+vid = pykms.VideoDevice("/dev/video10")
+
+src_streamer = vid.output_streamer
+dst_streamer = vid.capture_streamer
+
+src_streamer.set_format(ifmt, iw, ih)
+(left, top, width, height) = src_streamer.get_selection()
+print("get: crop -> {},{}-{}x{}".format(left, top, width, height))
+(left, top, width, height) = src_streamer.set_selection(160, 0, 320, 240)
+print("set: crop -> {},{}-{}x{}".format(left, top, width, height))
+
+dst_streamer.set_format(ofmt, ow, oh)
+
+src_streamer.set_queue_size(NUM_BUFS)
+dst_streamer.set_queue_size(NUM_BUFS)
+
+for fb in src_fbs:
+ src_streamer.queue(fb)
+
+for fb in dst_fbs:
+ dst_streamer.queue(fb)
+
+input("press enter\n")
+
+src_streamer.stream_on()
+dst_streamer.stream_on()
+
+loop_count = 0
+
+def readvid(conn, mask):
+ global loop_count
+ print("VID EVENT");
+
+ ifb = src_streamer.dequeue()
+ ofb = dst_streamer.dequeue()
+
+ req = pykms.AtomicReq(card)
+ req.add_plane(plane1, ifb, crtc, dst=(0, 0, 400, 480))
+ req.add_plane(plane2, ofb, crtc, dst=(400, 0, 400, 480))
+ req.commit_sync(allow_modeset = True)
+ time.sleep(1)
+ loop_count += 1
+ if loop_count >= 10:
+ exit(0)
+ print("loop #", loop_count)
+ src_streamer.queue(ifb)
+ dst_streamer.queue(ofb)
+
+
+def readkey(conn, mask):
+ print("KEY EVENT");
+ sys.stdin.readline()
+ exit(0)
+
+sel = selectors.PollSelector()
+sel.register(vid.fd, selectors.EVENT_READ, readvid)
+sel.register(sys.stdin, selectors.EVENT_READ, readkey)
+
+while True:
+ events = sel.select()
+ for key, mask in events:
+ callback = key.data
+ callback(key.fileobj, mask)
+
+print("done");
+exit(0)
diff --git a/utils/kmsblank.cpp b/utils/kmsblank.cpp
index 0b51810..286c7f7 100644
--- a/utils/kmsblank.cpp
+++ b/utils/kmsblank.cpp
@@ -27,7 +27,7 @@
int main(int argc, char **argv)
{
- string dev_path = "/dev/dri/card0";
+ string dev_path;
vector<string> conn_strs;
uint32_t time = 0;
diff --git a/utils/kmsprint.cpp b/utils/kmsprint.cpp
index 4d355fc..116fead 100644
--- a/utils/kmsprint.cpp
+++ b/utils/kmsprint.cpp
@@ -68,10 +68,17 @@
str = sformat("Connector %u (%u) %s",
c.idx(), c.id(), c.fullname().c_str());
- if (c.connected())
+ switch (c.connector_status()) {
+ case ConnectorStatus::Connected:
str += " (connected)";
- else
+ break;
+ case ConnectorStatus::Disconnected:
str += " (disconnected)";
+ break;
+ default:
+ str += " (unknown)";
+ break;
+ }
return str;
}
@@ -134,7 +141,7 @@
static string format_property(const Property* prop, uint64_t val)
{
- string ret = sformat("%s = ", prop->name().c_str());
+ string ret = sformat("%s (%u) = ", prop->name().c_str(), prop->id());
switch (prop->type()) {
case PropertyType::Bitmask:
@@ -477,10 +484,11 @@
static const char* usage_str =
"Usage: kmsprint [OPTIONS]\n\n"
"Options:\n"
- " -l, --list Print list instead of tree\n"
- " -m, --modes Print modes\n"
- " --xmode Print modes using X modeline\n"
- " -p, --props Print properties\n"
+ " --device=DEVICE DEVICE is the path to DRM card to open\n"
+ " -l, --list Print list instead of tree\n"
+ " -m, --modes Print modes\n"
+ " --xmode Print modes using X modeline\n"
+ " -p, --props Print properties\n"
;
static void usage()
@@ -490,7 +498,7 @@
int main(int argc, char **argv)
{
- string dev_path = "/dev/dri/card0";
+ string dev_path;
OptionSet optionset = {
Option("|device=", [&dev_path](string s)
diff --git a/utils/kmstest.cpp b/utils/kmstest.cpp
index 62b103f..8144117 100644
--- a/utils/kmstest.cpp
+++ b/utils/kmstest.cpp
@@ -234,7 +234,12 @@
EXIT("Failed to parse crtc option '%s'", crtc_str.c_str());
}
- if (!resman.reserve_crtc(output.crtc))
+ if (output.crtc)
+ output.crtc = resman.reserve_crtc(output.crtc);
+ else
+ output.crtc = resman.reserve_crtc(output.connector);
+
+ if (!output.crtc)
EXIT("Could not find available crtc");
}
@@ -439,7 +444,7 @@
string arg;
};
-static string s_device_path = "/dev/dri/card0";
+static string s_device_path;
static vector<Arg> parse_cmdline(int argc, char **argv)
{
@@ -632,9 +637,9 @@
}
if (outputs.empty()) {
- // no outputs defined, show a pattern on all screens
+ // no outputs defined, show a pattern on all connected screens
for (Connector* conn : card.get_connectors()) {
- if (!conn->connected())
+ if (conn->connector_status() != ConnectorStatus::Connected)
continue;
OutputInfo output = { };
@@ -686,10 +691,22 @@
return outputs;
}
+static char sync_to_char(SyncPolarity pol)
+{
+ switch (pol) {
+ case SyncPolarity::Positive:
+ return '+';
+ case SyncPolarity::Negative:
+ return '-';
+ default:
+ return '?';
+ }
+}
+
static std::string videomode_to_string(const Videomode& m)
{
- string h = sformat("%u/%u/%u/%u", m.hdisplay, m.hfp(), m.hsw(), m.hbp());
- string v = sformat("%u/%u/%u/%u", m.vdisplay, m.vfp(), m.vsw(), m.vbp());
+ string h = sformat("%u/%u/%u/%u/%c", m.hdisplay, m.hfp(), m.hsw(), m.hbp(), sync_to_char(m.hsync()));
+ string v = sformat("%u/%u/%u/%u/%c", m.vdisplay, m.vfp(), m.vsw(), m.vbp(), sync_to_char(m.vsync()));
return sformat("%s %.3f %s %s %u (%.2f) %#x %#x",
m.name.c_str(),
@@ -722,7 +739,7 @@
if (!o.legacy_fbs.empty()) {
auto fb = o.legacy_fbs[0];
- printf(" (Fb %u %ux%u-%s)", fb->id(), fb->width(), fb->height(), PixelFormatToFourCC(fb->format()).c_str());
+ printf(" Fb %u %ux%u-%s\n", fb->id(), fb->width(), fb->height(), PixelFormatToFourCC(fb->format()).c_str());
}
for (unsigned j = 0; j < o.planes.size(); ++j) {
@@ -764,30 +781,41 @@
}
for (const OutputInfo& o : outputs) {
+ int r;
auto conn = o.connector;
auto crtc = o.crtc;
- if (!o.conn_props.empty() || !o.crtc_props.empty())
- printf("WARNING: properties not set without atomic modesetting");
+ for (const PropInfo& prop : o.conn_props) {
+ r = conn->set_prop_value(prop.prop, prop.val);
+ EXIT_IF(r, "failed to set connector property %s\n", prop.name.c_str());
+ }
+
+ for (const PropInfo& prop : o.crtc_props) {
+ r = crtc->set_prop_value(prop.prop, prop.val);
+ EXIT_IF(r, "failed to set crtc property %s\n", prop.name.c_str());
+ }
if (!o.legacy_fbs.empty()) {
auto fb = o.legacy_fbs[0];
- int r = crtc->set_mode(conn, *fb, o.mode);
+ r = crtc->set_mode(conn, *fb, o.mode);
if (r)
printf("crtc->set_mode() failed for crtc %u: %s\n",
crtc->id(), strerror(-r));
}
for (const PlaneInfo& p : o.planes) {
+ for (const PropInfo& prop : p.props) {
+ r = p.plane->set_prop_value(prop.prop, prop.val);
+ EXIT_IF(r, "failed to set plane property %s\n", prop.name.c_str());
+ }
+
auto fb = p.fbs[0];
- int r = crtc->set_plane(p.plane, *fb,
+ r = crtc->set_plane(p.plane, *fb,
p.x, p.y, p.w, p.h,
0, 0, fb->width(), fb->height());
if (r)
printf("crtc->set_plane() failed for plane %u: %s\n",
p.plane->id(), strerror(-r));
- if (!p.props.empty())
- printf("WARNING: properties not set without atomic modesetting");
}
}
}
@@ -1085,6 +1113,9 @@
Card card(s_device_path);
+ if (!card.is_master())
+ EXIT("Could not get DRM master permission. Card already in use?");
+
if (!card.has_atomic() && s_flip_sync)
EXIT("Synchronized flipping requires atomic modesetting");
diff --git a/utils/kmsview.cpp b/utils/kmsview.cpp
index 04d005d..eea9dde 100644
--- a/utils/kmsview.cpp
+++ b/utils/kmsview.cpp
@@ -38,7 +38,7 @@
int main(int argc, char** argv)
{
uint32_t time = 0;
- string dev_path = "/dev/dri/card0";
+ string dev_path;
string conn_name;
OptionSet optionset = {
diff --git a/utils/wbm2m.cpp b/utils/wbm2m.cpp
index 4a126a8..b69bb28 100644
--- a/utils/wbm2m.cpp
+++ b/utils/wbm2m.cpp
@@ -2,6 +2,7 @@
#include <poll.h>
#include <unistd.h>
#include <algorithm>
+#include <regex>
#include <fstream>
#include <map>
#include <system_error>
@@ -19,7 +20,8 @@
static const char* usage_str =
"Usage: wbm2m [OPTIONS]\n\n"
"Options:\n"
- " -f, --format=4CC Output format"
+ " -f, --format=4CC Output format\n"
+ " -c, --crop=CROP CROP is <x>,<y>-<w>x<h>\n"
" -h, --help Print this help\n"
;
@@ -45,6 +47,21 @@
s_bar_pos_map[fb] = pos;
}
+static void parse_crop(const string& crop_str, uint32_t& c_left, uint32_t& c_top,
+ uint32_t& c_width, uint32_t& c_height)
+{
+ const regex crop_re("(\\d+),(\\d+)-(\\d+)x(\\d+)"); // 400,400-400x400
+
+ smatch sm;
+ if (!regex_match(crop_str, sm, crop_re))
+ EXIT("Failed to parse crop option '%s'", crop_str.c_str());
+
+ c_left = stoul(sm[1]);
+ c_top = stoul(sm[2]);
+ c_width = stoul(sm[3]);
+ c_height = stoul(sm[4]);
+}
+
int main(int argc, char** argv)
{
// XXX get from args
@@ -55,15 +72,21 @@
const uint32_t dst_width = 800;
const uint32_t dst_height = 480;
- auto dst_fmt = PixelFormat::XRGB8888;
+ uint32_t c_top, c_left, c_width, c_height;
- const string filename = "wb-out.raw";
+ auto dst_fmt = PixelFormat::XRGB8888;
+ bool use_selection = false;
OptionSet optionset = {
Option("f|format=", [&](string s)
{
dst_fmt = FourCCToPixelFormat(s);
}),
+ Option("c|crop=", [&](string s)
+ {
+ parse_crop(s, c_left, c_top, c_width, c_height);
+ use_selection = true;
+ }),
Option("h|help", [&]()
{
puts(usage_str);
@@ -78,6 +101,9 @@
exit(-1);
}
+ const string filename = sformat("wb-out-%ux%u_%4.4s.raw", dst_width, dst_height,
+ PixelFormatToFourCC(dst_fmt).c_str());
+
VideoDevice vid("/dev/video10");
Card card;
@@ -91,6 +117,11 @@
out->set_format(src_fmt, src_width, src_height);
in->set_format(dst_fmt, dst_width, dst_height);
+ if (use_selection) {
+ out->set_selection(c_left, c_top, c_width, c_height);
+ printf("crop -> %u,%u-%ux%u\n", c_left, c_top, c_width, c_height);
+ }
+
out->set_queue_size(NUM_SRC_BUFS);
in->set_queue_size(NUM_DST_BUFS);