Commit 9dc2f03d authored by Maksim Sisov's avatar Maksim Sisov Committed by Commit Bot

[ozone/common] Make gbm_wrapper to be compiled with system libgbm

This patch makes use of new minigbm APi names, which are aligned with
Linux libgbm.

Also, it defines certain definitions, which are different between
libgbm and minigbm.

What is more, it adds USING_MINIGBM for internal usage to be able
to distinguish between system linux gbm and minigbm.

Last but not least, drmPrimeHandleToFd is used in case of linux
system libgbm in order to be able to get mappable fds per each
plane, which is neede to add GpuMemoryBuffers support.

Bug: 869206, 578890, 820047
Change-Id: I0a743aef1c8bad2bb5792a58ab29abec45ea4585
Reviewed-on: https://chromium-review.googlesource.com/1158234
Commit-Queue: Maksim Sisov <msisov@igalia.com>
Reviewed-by: default avatarMichael Spang <spang@chromium.org>
Reviewed-by: default avatarRobert Kroeger <rjkroege@chromium.org>
Cr-Commit-Position: refs/heads/master@{#589475}
parent 570d2fe3
......@@ -4,7 +4,9 @@
#include "ui/ozone/common/linux/gbm_wrapper.h"
#include <fcntl.h>
#include <gbm.h>
#include <xf86drm.h>
#include "base/posix/eintr_wrapper.h"
#include "ui/gfx/buffer_format_util.h"
......@@ -14,6 +16,91 @@
namespace gbm_wrapper {
namespace {
// Minigbm and system linux gbm have some differences. There is no clear way how
// to distinguish linux gbm (Mesa, basically) and minigbm, which can be both
// third_party and minigbm. Thus, use GBM_BO_IMPORT_FD_PLANAR define to
// identify, which gbm is used.
#if defined(GBM_BO_IMPORT_FD_PLANAR)
// Minigbm defines GBM_BO_IMPORT_FD_PLANAR, which is unknown in linux gbm.
// Redefine it in a common define.
#define GBM_BO_IMPORT_FD_DATA GBM_BO_IMPORT_FD_PLANAR
// There are some methods, which require knowing whether minigbm is used or not.
#ifndef USING_MINIGBM
#define USING_MINIGBM
#endif // USING_MINIGBM
// Minigbm and system linux gbm have alike gbm_bo_import* structures, but some
// of the data variables have different type.
using gbm_bo_import_fd_data_with_modifier = struct gbm_import_fd_planar_data;
#else
// See comment above. Linux defines GBM_BO_IMPORT_FD_MODIFIER, thus, redefine it
// in a common define.
#define GBM_BO_IMPORT_FD_DATA GBM_BO_IMPORT_FD_MODIFIER
// See comment above.
using gbm_bo_import_fd_data_with_modifier = struct gbm_import_fd_modifier_data;
#endif
void InitializeImportData(uint32_t format,
const gfx::Size& size,
const std::vector<base::ScopedFD>& fds,
const std::vector<gfx::NativePixmapPlane>& planes,
gbm_bo_import_fd_data_with_modifier* fd_data) {
fd_data->width = size.width();
fd_data->height = size.height();
fd_data->format = format;
DCHECK_LE(planes.size(), 3u);
for (size_t i = 0; i < planes.size(); ++i) {
fd_data->fds[i] = fds[i < fds.size() ? i : 0].get();
fd_data->strides[i] = planes[i].stride;
fd_data->offsets[i] = planes[i].offset;
#if defined(USING_MINIGBM)
fd_data->format_modifiers[i] = planes[i].modifier;
#else
fd_data->modifier = planes[i].modifier;
#endif
}
}
int GetPlaneFdForBo(gbm_bo* bo, size_t plane) {
DCHECK(plane < gbm_bo_get_plane_count(bo));
// System linux gbm (or Mesa gbm) does not provide fds per plane basis. Thus,
// get plane handle and use drm ioctl to get a prime fd out of it avoid having
// two different branches for minigbm and Mesa gbm here.
gbm_device* gbm_dev = gbm_bo_get_device(bo);
int dev_fd = gbm_device_get_fd(gbm_dev);
if (dev_fd <= 0) {
LOG(ERROR) << "Unable to get device fd";
return -1;
}
const uint32_t plane_handle = gbm_bo_get_handle_for_plane(bo, plane).u32;
int fd = -1;
int ret;
// Use DRM_RDWR to allow the fd to be mappable in another process.
ret = drmPrimeHandleToFD(dev_fd, plane_handle, DRM_CLOEXEC | DRM_RDWR, &fd);
// Older DRM implementations blocked DRM_RDWR, but gave a read/write mapping
// anyways
if (ret)
ret = drmPrimeHandleToFD(dev_fd, plane_handle, DRM_CLOEXEC, &fd);
return ret ? ret : fd;
}
size_t GetSizeOfPlane(gbm_bo* bo, size_t plane) {
// System linux gbm (or Mesa gbm) does not provide plane size. Thus, calculate
// it by ourselves and avoid having two different branches for minigbm and
// Mesa gbm here.
return gbm_bo_get_height(bo) * gbm_bo_get_stride_for_plane(bo, plane);
}
} // namespace
class Buffer final : public ui::GbmBuffer {
public:
Buffer(struct gbm_bo* bo,
......@@ -72,7 +159,7 @@ class Buffer final : public ui::GbmBuffer {
}
uint32_t GetPlaneHandle(size_t plane) const override {
DCHECK_LT(plane, planes_.size());
return gbm_bo_get_plane_handle(bo_, plane).u32;
return gbm_bo_get_handle_for_plane(bo_, plane).u32;
}
uint32_t GetHandle() const override { return gbm_bo_get_handle(bo_).u32; }
gfx::NativePixmapHandle ExportHandle() const override {
......@@ -121,11 +208,18 @@ std::unique_ptr<Buffer> CreateBufferForBO(struct gbm_bo* bo,
std::vector<base::ScopedFD> fds;
std::vector<gfx::NativePixmapPlane> planes;
const uint64_t modifier = gbm_bo_get_format_modifier(bo);
for (size_t i = 0; i < gbm_bo_get_num_planes(bo); ++i) {
const uint64_t modifier = gbm_bo_get_modifier(bo);
const int plane_count = gbm_bo_get_plane_count(bo);
// The Mesa's gbm implementation explicitly checks whether plane count <= and
// returns 1 if the condition is true. Nevertheless, use a DCHECK here to make
// sure the condition is not broken there.
DCHECK(plane_count > 0);
// Ensure there are no differences in integer signs by casting any possible
// values to size_t.
for (size_t i = 0; i < static_cast<size_t>(plane_count); ++i) {
// The fd returned by gbm_bo_get_fd is not ref-counted and need to be
// kept open for the lifetime of the buffer.
base::ScopedFD fd(gbm_bo_get_plane_fd(bo, i));
base::ScopedFD fd(GetPlaneFdForBo(bo, i));
// TODO(dcastagna): support multiple fds.
// crbug.com/642410
......@@ -138,9 +232,9 @@ std::unique_ptr<Buffer> CreateBufferForBO(struct gbm_bo* bo,
fds.emplace_back(std::move(fd));
}
planes.emplace_back(gbm_bo_get_plane_stride(bo, i),
gbm_bo_get_plane_offset(bo, i),
gbm_bo_get_plane_size(bo, i), modifier);
planes.emplace_back(gbm_bo_get_stride_for_plane(bo, i),
gbm_bo_get_offset(bo, i), GetSizeOfPlane(bo, i),
modifier);
}
return std::make_unique<Buffer>(bo, format, flags, modifier, std::move(fds),
size, std::move(planes));
......@@ -187,28 +281,21 @@ class Device final : public ui::GbmDevice {
DCHECK_EQ(planes[0].offset, 0);
// Try to use scanout if supported.
int gbm_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_TEXTURING;
int gbm_flags = GBM_BO_USE_SCANOUT;
#if defined(GBM_BO_USE_TEXTURING)
gbm_flags |= GBM_BO_USE_TEXTURING;
#endif
if (!gbm_device_is_format_supported(device_, format, gbm_flags))
gbm_flags &= ~GBM_BO_USE_SCANOUT;
struct gbm_bo* bo = nullptr;
if (gbm_device_is_format_supported(device_, format, gbm_flags)) {
struct gbm_import_fd_planar_data fd_data;
fd_data.width = size.width();
fd_data.height = size.height();
fd_data.format = format;
DCHECK_LE(planes.size(), 3u);
for (size_t i = 0; i < planes.size(); ++i) {
fd_data.fds[i] = fds[i < fds.size() ? i : 0].get();
fd_data.strides[i] = planes[i].stride;
fd_data.offsets[i] = planes[i].offset;
fd_data.format_modifiers[i] = planes[i].modifier;
}
gbm_bo_import_fd_data_with_modifier fd_data;
InitializeImportData(format, size, fds, planes, &fd_data);
// The fd passed to gbm_bo_import is not ref-counted and need to be
// kept open for the lifetime of the buffer.
bo = gbm_bo_import(device_, GBM_BO_IMPORT_FD_PLANAR, &fd_data, gbm_flags);
bo = gbm_bo_import(device_, GBM_BO_IMPORT_FD_DATA, &fd_data, gbm_flags);
if (!bo) {
LOG(ERROR) << "nullptr returned from gbm_bo_import";
return nullptr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment