blob: 8c1be5e4cda781592a9a21d75961466d5ff60c7a [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/drm/common/client_native_pixmap_dmabuf.h"
#include <fcntl.h>
#include <stddef.h>
#include <sys/mman.h>
#include <xf86drm.h>
#include "base/memory/ptr_util.h"
#include "base/process/memory.h"
#include "base/trace_event/trace_event.h"
#if defined(USE_OZONE)
// TODO(vignatti): replace the local definitions below with #include
// <linux/dma-buf.h> once kernel version 4.6 becomes widely used.
#include <linux/types.h>
struct local_dma_buf_sync {
__u64 flags;
};
#define LOCAL_DMA_BUF_SYNC_READ (1 << 0)
#define LOCAL_DMA_BUF_SYNC_WRITE (2 << 0)
#define LOCAL_DMA_BUF_SYNC_RW \
(LOCAL_DMA_BUF_SYNC_READ | LOCAL_DMA_BUF_SYNC_WRITE)
#define LOCAL_DMA_BUF_SYNC_START (0 << 2)
#define LOCAL_DMA_BUF_SYNC_END (1 << 2)
#define LOCAL_DMA_BUF_BASE 'b'
#define LOCAL_DMA_BUF_IOCTL_SYNC \
_IOW(LOCAL_DMA_BUF_BASE, 0, struct local_dma_buf_sync)
#endif
namespace ui {
namespace {
void PrimeSyncStart(int dmabuf_fd) {
struct local_dma_buf_sync sync_start = {0};
sync_start.flags = LOCAL_DMA_BUF_SYNC_START | LOCAL_DMA_BUF_SYNC_RW;
if (drmIoctl(dmabuf_fd, LOCAL_DMA_BUF_IOCTL_SYNC, &sync_start))
PLOG(ERROR) << "Failed DMA_BUF_SYNC_START";
}
void PrimeSyncEnd(int dmabuf_fd) {
struct local_dma_buf_sync sync_end = {0};
sync_end.flags = LOCAL_DMA_BUF_SYNC_END | LOCAL_DMA_BUF_SYNC_RW;
if (drmIoctl(dmabuf_fd, LOCAL_DMA_BUF_IOCTL_SYNC, &sync_end))
PLOG(ERROR) << "Failed DMA_BUF_SYNC_END";
}
} // namespace
// static
std::unique_ptr<ClientNativePixmap> ClientNativePixmapDmaBuf::ImportFromDmabuf(
const gfx::NativePixmapHandle& handle,
const gfx::Size& size) {
return base::WrapUnique(new ClientNativePixmapDmaBuf(handle, size));
}
ClientNativePixmapDmaBuf::ClientNativePixmapDmaBuf(
const gfx::NativePixmapHandle& handle,
const gfx::Size& size)
: pixmap_handle_(handle), size_(size), data_{0} {
TRACE_EVENT0("drm", "ClientNativePixmapDmaBuf");
// TODO(dcastagna): support multiple fds.
DCHECK_EQ(1u, handle.fds.size());
DCHECK_GE(handle.fds.front().fd, 0);
dmabuf_fd_.reset(handle.fds.front().fd);
DCHECK_GE(handle.planes.back().size, 0u);
size_t map_size = handle.planes.back().offset + handle.planes.back().size;
data_ = mmap(nullptr, map_size, (PROT_READ | PROT_WRITE), MAP_SHARED,
dmabuf_fd_.get(), 0);
if (data_ == MAP_FAILED) {
PLOG(ERROR) << "Failed mmap().";
base::TerminateBecauseOutOfMemory(map_size);
}
}
ClientNativePixmapDmaBuf::~ClientNativePixmapDmaBuf() {
TRACE_EVENT0("drm", "~ClientNativePixmapDmaBuf");
size_t map_size =
pixmap_handle_.planes.back().offset + pixmap_handle_.planes.back().size;
int ret = munmap(data_, map_size);
DCHECK(!ret);
}
bool ClientNativePixmapDmaBuf::Map() {
TRACE_EVENT0("drm", "DmaBuf:Map");
if (data_ != nullptr) {
PrimeSyncStart(dmabuf_fd_.get());
return true;
}
return false;
}
void ClientNativePixmapDmaBuf::Unmap() {
TRACE_EVENT0("drm", "DmaBuf:Unmap");
PrimeSyncEnd(dmabuf_fd_.get());
}
void* ClientNativePixmapDmaBuf::GetMemoryAddress(size_t plane) const {
DCHECK_LT(plane, pixmap_handle_.planes.size());
uint8_t* address = reinterpret_cast<uint8_t*>(data_);
return address + pixmap_handle_.planes[plane].offset;
}
int ClientNativePixmapDmaBuf::GetStride(size_t plane) const {
DCHECK_LT(plane, pixmap_handle_.planes.size());
return pixmap_handle_.planes[plane].stride;
}
} // namespace ui