In DRM preview, zoom the input image to fit the screen.
1. Use the atomic drm mode. 2. Find a mode in the connector with most closed area with the input image. 3. Set the plane property to scale the input image. Signed-off-by: zejian.su <zejian.su@starfivetech.com>
This commit is contained in:
+300
@@ -0,0 +1,300 @@
|
||||
From 526cbca855ea6310dc846cc05158d403aea456e1 Mon Sep 17 00:00:00 2001
|
||||
From: "zejian.su" <zejian.su@starfivetech.com>
|
||||
Date: Mon, 27 Nov 2023 18:02:17 +0800
|
||||
Subject: [PATCH 1/2] In DRM preview, zoom the input image to fit the screen.
|
||||
|
||||
1. Use the atomic drm mode.
|
||||
2. Find a mode in the connector with most closed area with the input image.
|
||||
3. Set the plane property to scale the input image.
|
||||
|
||||
Signed-off-by: zejian.su <zejian.su@starfivetech.com>
|
||||
---
|
||||
preview/drm_preview.cpp | 184 ++++++++++++++++++++++++++++++++--------
|
||||
1 file changed, 147 insertions(+), 37 deletions(-)
|
||||
|
||||
diff --git a/preview/drm_preview.cpp b/preview/drm_preview.cpp
|
||||
index 38fc6a2..405bdca 100644
|
||||
--- a/preview/drm_preview.cpp
|
||||
+++ b/preview/drm_preview.cpp
|
||||
@@ -17,6 +17,92 @@
|
||||
|
||||
#include "preview.hpp"
|
||||
|
||||
+class DRMObject
|
||||
+{
|
||||
+public:
|
||||
+ DRMObject(int drmfd, uint32_t id, uint32_t type)
|
||||
+ : id_(id), type_(type){
|
||||
+ drmModeObjectProperties *properties = drmModeObjectGetProperties(drmfd, id, type);
|
||||
+ if (!properties)
|
||||
+ return;
|
||||
+
|
||||
+ drmModePropertyPtr property;
|
||||
+ for (uint32_t i = 0; i < properties->count_props; i++) {
|
||||
+ property = drmModeGetProperty(drmfd, properties->props[i]);
|
||||
+ property_[std::string(property->name)] = property->prop_id;
|
||||
+ drmModeFreeProperty(property);
|
||||
+ }
|
||||
+
|
||||
+ drmModeFreeObjectProperties(properties);
|
||||
+ }
|
||||
+
|
||||
+ uint32_t getID() const {return id_;};
|
||||
+
|
||||
+public:
|
||||
+ std::unordered_map<std::string, uint32_t> property_;
|
||||
+
|
||||
+private:
|
||||
+ uint32_t id_;
|
||||
+ uint32_t type_;
|
||||
+};
|
||||
+
|
||||
+class AtomicRequest
|
||||
+{
|
||||
+public:
|
||||
+ enum Flags {
|
||||
+ FlagAllowModeset = (1 << 0),
|
||||
+ FlagAsync = (1 << 1),
|
||||
+ FlagTestOnly = (1 << 2),
|
||||
+ };
|
||||
+
|
||||
+ AtomicRequest() : valid_(true) {
|
||||
+ request_ = drmModeAtomicAlloc();
|
||||
+ if (!request_)
|
||||
+ valid_ = false;
|
||||
+ }
|
||||
+
|
||||
+ ~AtomicRequest() {
|
||||
+ if (request_)
|
||||
+ drmModeAtomicFree(request_);
|
||||
+ }
|
||||
+
|
||||
+ bool isValid() const { return valid_; }
|
||||
+
|
||||
+ int addProperty(int drmfd, const DRMObject *object, const std::string &propertyName,
|
||||
+ uint64_t value) {
|
||||
+
|
||||
+ if (!valid_)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ auto it = object->property_.find(propertyName);
|
||||
+ if(it == object->property_.end())
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if(drmModeAtomicAddProperty(request_, object->getID(), it->second, value) < 0) {
|
||||
+ std::string errMsg = "drmModeAtomicAddProperty() failed -- object: " +
|
||||
+ std::to_string(object->getID()) + ", property: " + std::to_string(it->second);
|
||||
+ throw std::runtime_error(errMsg);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ int commit(int drmfd, unsigned int flags = 0) {
|
||||
+ if(drmModeAtomicCommit(drmfd, request_, flags, NULL) < 0)
|
||||
+ throw std::runtime_error("drmModeAtomicCommit() failed");
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+private:
|
||||
+ AtomicRequest(const AtomicRequest &) = delete;
|
||||
+ AtomicRequest(const AtomicRequest &&) = delete;
|
||||
+ AtomicRequest &operator=(const AtomicRequest &) = delete;
|
||||
+ AtomicRequest &operator=(const AtomicRequest &&) = delete;
|
||||
+
|
||||
+ bool valid_;
|
||||
+ drmModeAtomicReq *request_;
|
||||
+};
|
||||
+
|
||||
class DrmPreview : public Preview
|
||||
{
|
||||
public:
|
||||
@@ -48,6 +134,7 @@ private:
|
||||
void makeBuffer(int fd, size_t size, StreamInfo const &info, Buffer &buffer);
|
||||
void findCrtc();
|
||||
void findPlane();
|
||||
+ void fitDisplaySize();
|
||||
int drmfd_;
|
||||
int conId_;
|
||||
drmModeConnector *con_;
|
||||
@@ -61,11 +148,18 @@ private:
|
||||
unsigned int height_;
|
||||
unsigned int screen_width_;
|
||||
unsigned int screen_height_;
|
||||
+ unsigned int display_x_;
|
||||
+ unsigned int display_y_;
|
||||
+ unsigned int display_w_;
|
||||
+ unsigned int display_h_;
|
||||
std::map<int, Buffer> buffers_; // map the DMABUF's fd to the Buffer
|
||||
int last_fd_;
|
||||
unsigned int max_image_width_;
|
||||
unsigned int max_image_height_;
|
||||
bool first_time_;
|
||||
+
|
||||
+ std::unique_ptr<DRMObject> connector_;
|
||||
+ std::unique_ptr<DRMObject> crtc_;
|
||||
};
|
||||
|
||||
#define ERRSTR strerror(errno)
|
||||
@@ -96,10 +190,6 @@ void DrmPreview::findCrtc()
|
||||
if (con->encoder_id)
|
||||
{
|
||||
enc = drmModeGetEncoder(drmfd_, con->encoder_id);
|
||||
- //if (enc->crtc_id)
|
||||
- //{
|
||||
- // crtc = drmModeGetCrtc(drmfd_, enc->crtc_id);
|
||||
- //}
|
||||
} else
|
||||
{
|
||||
enc = drmModeGetEncoder(drmfd_, con->encoders[0]);
|
||||
@@ -229,6 +319,7 @@ void DrmPreview::findPlane()
|
||||
drmModeFreePlane(plane);
|
||||
break;
|
||||
}
|
||||
+ planeId_ = planes->planes[0];
|
||||
}
|
||||
catch (std::exception const &e)
|
||||
{
|
||||
@@ -265,21 +356,16 @@ DrmPreview::DrmPreview(Options const *options) : Preview(options), last_fd_(-1),
|
||||
//out_fourcc_ = DRM_FORMAT_YUV420;
|
||||
out_fourcc_ = DRM_FORMAT_NV12;
|
||||
findPlane();
|
||||
+
|
||||
+ drmSetClientCap(drmfd_, DRM_CLIENT_CAP_ATOMIC, 1);
|
||||
+ connector_ = std::make_unique<DRMObject>(drmfd_, conId_, DRM_MODE_OBJECT_CONNECTOR);
|
||||
+ crtc_ = std::make_unique<DRMObject>(drmfd_, crtcId_, DRM_MODE_OBJECT_CRTC);
|
||||
}
|
||||
catch (std::exception const &e)
|
||||
{
|
||||
close(drmfd_);
|
||||
throw;
|
||||
}
|
||||
-
|
||||
- // Default behaviour here is to go fullscreen.
|
||||
- if (options_->fullscreen || width_ == 0 || height_ == 0 || x_ + width_ > screen_width_ ||
|
||||
- y_ + height_ > screen_height_)
|
||||
- {
|
||||
- x_ = y_ = 0;
|
||||
- width_ = screen_width_;
|
||||
- height_ = screen_height_;
|
||||
- }
|
||||
}
|
||||
|
||||
DrmPreview::~DrmPreview()
|
||||
@@ -365,9 +451,23 @@ static void setup_colour_space(int fd, int plane_id, std::optional<libcamera::Co
|
||||
drm_set_property(fd, plane_id, "COLOR_RANGE", range);
|
||||
}
|
||||
|
||||
+void DrmPreview::fitDisplaySize()
|
||||
+{
|
||||
+ if((int64_t)width_ * screen_height_ > (int64_t)screen_width_ * height_) {
|
||||
+ display_x_ = 0, display_w_ = screen_width_;
|
||||
+ display_h_ = ((int64_t)screen_width_ * height_) / (int64_t)width_;
|
||||
+ display_y_ = (screen_height_ - display_h_) >> 1;
|
||||
+ } else {
|
||||
+ display_y_ = 0, display_h_ = screen_height_;
|
||||
+ display_w_ = ((int64_t)width_ * screen_height_) / (int64_t)height_;
|
||||
+ display_x_ = (screen_width_ - display_w_) >> 1;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void DrmPreview::makeBuffer(int fd, size_t size, StreamInfo const &info, Buffer &buffer)
|
||||
{
|
||||
unsigned int width = info.width, height = info.height, stride = info.stride;
|
||||
+ int64_t targetArea = 0;
|
||||
if (first_time_)
|
||||
{
|
||||
first_time_ = false;
|
||||
@@ -379,6 +479,10 @@ void DrmPreview::makeBuffer(int fd, size_t size, StreamInfo const &info, Buffer
|
||||
buffer.size = size;
|
||||
buffer.info = info;
|
||||
|
||||
+ if(!width_ || !height)
|
||||
+ width_ = info.width, height_ = info.height;
|
||||
+ targetArea = (int64_t)width_ * height_;
|
||||
+
|
||||
if (drmPrimeFDToHandle(drmfd_, fd, &buffer.bo_handle))
|
||||
throw std::runtime_error("drmPrimeFDToHandle failed for fd " + std::to_string(fd));
|
||||
|
||||
@@ -401,33 +505,46 @@ void DrmPreview::makeBuffer(int fd, size_t size, StreamInfo const &info, Buffer
|
||||
|
||||
/* find preferred mode */
|
||||
drmModeModeInfo *modeptr = NULL, *preferred = NULL;
|
||||
+ int64_t minDiff = -1;
|
||||
for (int m = 0; m < con_->count_modes; m++) {
|
||||
+ int64_t area, areaDiff;
|
||||
modeptr = &con_->modes[m];
|
||||
- if (modeptr->hdisplay == width && modeptr->vdisplay == height) {
|
||||
+
|
||||
+ area = (int64_t)modeptr->hdisplay * modeptr->vdisplay;
|
||||
+ areaDiff = abs(targetArea - area);
|
||||
+ if(-1 == minDiff)
|
||||
+ minDiff = abs(targetArea - area), preferred = modeptr;
|
||||
+ else {
|
||||
+ if(areaDiff < minDiff)
|
||||
+ minDiff = areaDiff, preferred = modeptr;
|
||||
+ }
|
||||
+
|
||||
+ if (!minDiff) {
|
||||
preferred = modeptr;
|
||||
std::cout << "find the matched mode, modes index= "
|
||||
<< m << ", " << width << "x" << height << std::endl;
|
||||
break;
|
||||
}
|
||||
- if (modeptr->type & DRM_MODE_TYPE_PREFERRED) {
|
||||
- preferred = modeptr;
|
||||
- std::cout << "find perferred mode, modes index= " << m << std::endl;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (!preferred)
|
||||
- preferred = &con_->modes[0];
|
||||
-
|
||||
- // set default
|
||||
- if (drmModeSetCrtc(drmfd_, crtcId_, buffer.fb_handle, 0, 0,
|
||||
- (uint32_t *)&conId_, 1, preferred)) {
|
||||
- throw std::runtime_error("drmModeSetCrtc() failed");
|
||||
}
|
||||
|
||||
screen_width_ = preferred->hdisplay;
|
||||
screen_height_ = preferred->vdisplay;
|
||||
- width_ = width;
|
||||
- height_ = height;
|
||||
+ fitDisplaySize();
|
||||
+
|
||||
+ AtomicRequest ar;
|
||||
+ uint32_t blob_id;
|
||||
+
|
||||
+ drmModeCreatePropertyBlob(drmfd_, preferred, sizeof(con_->modes[0]), &blob_id);
|
||||
+ ar.addProperty(drmfd_, connector_.get(), "CRTC_ID", crtcId_);
|
||||
+ ar.addProperty(drmfd_, crtc_.get(), "ACTIVE", 1);
|
||||
+ ar.addProperty(drmfd_, crtc_.get(), "MODE_ID", blob_id);
|
||||
+ ar.commit(drmfd_, DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_ATOMIC_ALLOW_MODESET);
|
||||
+
|
||||
+ // set default
|
||||
+ //if (drmModeSetCrtc(drmfd_, crtcId_, buffer.fb_handle, 0, 0,
|
||||
+ // (uint32_t *)&conId_, 1, preferred)) {
|
||||
+ // throw std::runtime_error("drmModeSetCrtc() failed");
|
||||
+ //}
|
||||
}
|
||||
|
||||
void DrmPreview::Show(int fd, libcamera::Span<uint8_t> span, StreamInfo const &info)
|
||||
@@ -436,14 +553,7 @@ void DrmPreview::Show(int fd, libcamera::Span<uint8_t> span, StreamInfo const &i
|
||||
if (buffer.fd == -1)
|
||||
makeBuffer(fd, span.size(), info, buffer);
|
||||
|
||||
- unsigned int x_off = 0, y_off = 0;
|
||||
- unsigned int w = width_, h = height_;
|
||||
- if (info.width * height_ > width_ * info.height)
|
||||
- h = width_ * info.height / info.width, y_off = (height_ - h) / 2;
|
||||
- else
|
||||
- w = height_ * info.width / info.height, x_off = (width_ - w) / 2;
|
||||
-
|
||||
- if (drmModeSetPlane(drmfd_, planeId_, crtcId_, buffer.fb_handle, 0, x_off + x_, y_off + y_, w, h, 0, 0,
|
||||
+ if (drmModeSetPlane(drmfd_, planeId_, crtcId_, buffer.fb_handle, 0, display_x_, display_y_, display_w_, display_h_, 0, 0,
|
||||
buffer.info.width << 16, buffer.info.height << 16))
|
||||
throw std::runtime_error("drmModeSetPlane failed: " + std::string(ERRSTR));
|
||||
if (last_fd_ >= 0)
|
||||
--
|
||||
2.34.1
|
||||
|
||||
Reference in New Issue
Block a user