| Index: content/common/gpu/client/gpu_memory_buffer_impl_intel_drm.cc
|
| diff --git a/content/common/gpu/client/gpu_memory_buffer_impl_intel_drm.cc b/content/common/gpu/client/gpu_memory_buffer_impl_intel_drm.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..78e698c403ce97bbe8ce1d8f3aa4a29a499b7f5f
|
| --- /dev/null
|
| +++ b/content/common/gpu/client/gpu_memory_buffer_impl_intel_drm.cc
|
| @@ -0,0 +1,325 @@
|
| +// Copyright 2014 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 "content/common/gpu/client/gpu_memory_buffer_impl_intel_drm.h"
|
| +
|
| +extern "C" {
|
| +#include <fcntl.h>
|
| +#include <libdrm/i915_drm.h>
|
| +#include <libdrm/intel_bufmgr.h>
|
| +#include <xf86drm.h>
|
| +#if defined(USE_X11)
|
| +#include <X11/Xlib.h>
|
| +#include <X11/Xlibint.h>
|
| +#include <X11/extensions/Xext.h>
|
| +#include <X11/extensions/extutil.h>
|
| +#include <X11/extensions/dri2proto.h>
|
| +// X11/Xlibint.h define min/max macros which will conflict with std::min/max
|
| +// unless we undefine them here.
|
| +#undef min
|
| +#undef max
|
| +#endif
|
| +}
|
| +
|
| +#include "base/debug/trace_event.h"
|
| +#include "base/files/scoped_file.h"
|
| +#include "base/lazy_instance.h"
|
| +#include "base/logging.h"
|
| +#include "base/numerics/safe_conversions.h"
|
| +#include "base/strings/stringprintf.h"
|
| +#include "base/threading/thread_checker.h"
|
| +#include "ui/gl/gl_bindings.h"
|
| +
|
| +#if defined(USE_X11)
|
| +#include "ui/gfx/x/x11_types.h"
|
| +#endif
|
| +
|
| +namespace content {
|
| +namespace {
|
| +
|
| +#if defined(USE_X11)
|
| +static char g_dri2_extension_name[] = DRI2_NAME;
|
| +static XExtensionInfo* g_dri2_info;
|
| +static XExtensionHooks g_dri2_extension_hooks = {NULL, // create_gc
|
| + NULL, // copy_gc
|
| + NULL, // flush_gc
|
| + NULL, // free_gc
|
| + NULL, // create_font
|
| + NULL, // free_font
|
| + NULL, // close_display
|
| + NULL, // wire_to_event
|
| + NULL, // event_to_wire
|
| + NULL, // error
|
| + NULL, // error_string
|
| +};
|
| +static XEXT_GENERATE_FIND_DISPLAY(DRI2FindDisplay,
|
| + g_dri2_info,
|
| + g_dri2_extension_name,
|
| + &g_dri2_extension_hooks,
|
| + 0,
|
| + NULL);
|
| +
|
| +bool X11DRI2Authenticate(drm_magic_t magic) {
|
| + Display* dpy = gfx::GetXDisplay();
|
| + XExtDisplayInfo* info = DRI2FindDisplay(dpy);
|
| + XextCheckExtension(dpy, info, g_dri2_extension_name, false);
|
| + LockDisplay(dpy);
|
| + xDRI2AuthenticateReq* req;
|
| + GetReq(DRI2Authenticate, req);
|
| + req->reqType = info->codes->major_opcode;
|
| + req->dri2ReqType = X_DRI2Authenticate;
|
| + req->window = DefaultRootWindow(dpy);
|
| + req->magic = magic;
|
| + xDRI2AuthenticateReply rep;
|
| + int status = _XReply(dpy, reinterpret_cast<xReply*>(&rep), 0, xFalse);
|
| + UnlockDisplay(dpy);
|
| + SyncHandle();
|
| + return status && rep.authenticated;
|
| +}
|
| +#endif // USE_X11
|
| +
|
| +const int kDeviceId = 0;
|
| +const int kBatchSize = 2048;
|
| +
|
| +int WriteEnable(gfx::GpuMemoryBuffer::AccessMode mode) {
|
| + switch (mode) {
|
| + case gfx::GpuMemoryBuffer::READ_ONLY:
|
| + return 0;
|
| + case gfx::GpuMemoryBuffer::WRITE_ONLY:
|
| + case gfx::GpuMemoryBuffer::READ_WRITE:
|
| + return 1;
|
| + }
|
| +
|
| + NOTREACHED();
|
| + return 0;
|
| +}
|
| +
|
| +bool IsHandleValid(const base::FileDescriptor& handle) {
|
| + return handle.fd >= 0;
|
| +}
|
| +
|
| +// Aligns 'value' by rounding it up to the next multiple of 'alignment'
|
| +uint64 AlignValue(uint64 value, int alignment) {
|
| + return value + (alignment - (value % alignment)) % alignment;
|
| +}
|
| +
|
| +uint64 BufferObjectStride(gfx::Size size, unsigned internalformat) {
|
| + uint64 stride = static_cast<uint64>(size.width()) *
|
| + GpuMemoryBufferImpl::BytesPerPixel(internalformat);
|
| +
|
| + // Note: Intel DRM API doesn't provide an interface that allows us to compute
|
| + // or query the stride. This should match the driver when untiled.
|
| + return AlignValue(stride, 64);
|
| +}
|
| +
|
| +class BufferObjectFactory {
|
| + public:
|
| + BufferObjectFactory() : buffer_manager_(NULL) {
|
| + std::string dev_name(
|
| + base::StringPrintf(DRM_DEV_NAME, DRM_DIR_NAME, kDeviceId));
|
| + base::ScopedFD dri_fd(open(dev_name.c_str(), O_RDWR));
|
| + if (dri_fd.get() < 0) {
|
| + LOG(ERROR) << "Failed to open: " << dev_name;
|
| + return;
|
| + }
|
| +
|
| +#if defined(USE_X11)
|
| + drm_magic_t magic;
|
| + if (drmGetMagic(dri_fd.get(), &magic))
|
| + return;
|
| +
|
| + if (!X11DRI2Authenticate(magic)) {
|
| + LOG(ERROR) << "DRI2Authenticate failed.";
|
| + return;
|
| + }
|
| +#endif
|
| +
|
| + buffer_manager_ = drm_intel_bufmgr_gem_init(dri_fd.get(), kBatchSize);
|
| + if (!buffer_manager_) {
|
| + LOG(ERROR) << "drm_intel_bufmgr_gem_init failed.";
|
| + return;
|
| + }
|
| +
|
| + dri_fd_.swap(dri_fd);
|
| + }
|
| + ~BufferObjectFactory() {
|
| + if (buffer_manager_)
|
| + drm_intel_bufmgr_destroy(buffer_manager_);
|
| + }
|
| +
|
| + drm_intel_bo* CreateBufferObject(gfx::Size size, unsigned internalformat) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + if (!buffer_manager_)
|
| + return NULL;
|
| +
|
| + uint64 expected_stride = BufferObjectStride(size, internalformat);
|
| + if (!base::IsValueInRangeForNumericType<uint32>(expected_stride))
|
| + return NULL;
|
| +
|
| + uint32_t tiling_mode = I915_TILING_NONE;
|
| + unsigned long stride = 0;
|
| + drm_intel_bo* buffer_object = drm_intel_bo_alloc_tiled(
|
| + buffer_manager_,
|
| + "chromium-gpu-memory-buffer",
|
| + size.width(),
|
| + size.height(),
|
| + GpuMemoryBufferImpl::BytesPerPixel(internalformat),
|
| + &tiling_mode,
|
| + &stride,
|
| + 0);
|
| + if (!buffer_object) {
|
| + LOG(ERROR) << "drm_intel_bo_alloc_tiled failed.";
|
| + return NULL;
|
| + }
|
| +
|
| + // This might fail if the stride computed by BufferObjectStride() doesn't
|
| + // match that of the driver.
|
| + if (static_cast<uint64>(stride) != expected_stride) {
|
| + LOG(ERROR) << "Unexpected stride: " << stride << " vs "
|
| + << expected_stride;
|
| + drm_intel_bo_unreference(buffer_object);
|
| + return NULL;
|
| + }
|
| +
|
| + return buffer_object;
|
| + }
|
| +
|
| + drm_intel_bo* CreateBufferObjectFromPrimeFd(gfx::Size size,
|
| + unsigned internalformat,
|
| + int prime_fd) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + if (!buffer_manager_)
|
| + return NULL;
|
| +
|
| + uint64 stride = BufferObjectStride(size, internalformat);
|
| + if (!base::IsValueInRangeForNumericType<uint32>(stride))
|
| + return NULL;
|
| +
|
| + uint64 buffer_size = stride * size.height();
|
| + if (!base::IsValueInRangeForNumericType<int>(buffer_size))
|
| + return NULL;
|
| +
|
| + return drm_intel_bo_gem_create_from_prime(
|
| + buffer_manager_, prime_fd, buffer_size);
|
| + }
|
| +
|
| + private:
|
| + base::ThreadChecker thread_checker_;
|
| + base::ScopedFD dri_fd_;
|
| + drm_intel_bufmgr* buffer_manager_;
|
| +};
|
| +base::LazyInstance<BufferObjectFactory>::Leaky g_buffer_object_factory =
|
| + LAZY_INSTANCE_INITIALIZER;
|
| +
|
| +} // namespace
|
| +
|
| +GpuMemoryBufferImplIntelDRM::GpuMemoryBufferImplIntelDRM(
|
| + gfx::Size size,
|
| + unsigned internalformat)
|
| + : GpuMemoryBufferImpl(size, internalformat), buffer_object_(NULL) {}
|
| +
|
| +GpuMemoryBufferImplIntelDRM::~GpuMemoryBufferImplIntelDRM() {
|
| + if (buffer_object_)
|
| + drm_intel_bo_unreference(buffer_object_);
|
| +}
|
| +
|
| +// static
|
| +bool GpuMemoryBufferImplIntelDRM::IsFormatSupported(unsigned internalformat) {
|
| + switch (internalformat) {
|
| + case GL_BGRA8_EXT:
|
| + return true;
|
| + default:
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +// static
|
| +drm_intel_bo* GpuMemoryBufferImplIntelDRM::CreateBufferObject(
|
| + gfx::Size size,
|
| + unsigned internalformat) {
|
| + return g_buffer_object_factory.Pointer()->CreateBufferObject(size,
|
| + internalformat);
|
| +}
|
| +
|
| +// static
|
| +bool GpuMemoryBufferImplIntelDRM::AllocateBufferObject(
|
| + gfx::Size size,
|
| + unsigned internalformat,
|
| + base::SharedMemoryHandle* handle) {
|
| + drm_intel_bo* buffer_object = CreateBufferObject(size, internalformat);
|
| + if (!buffer_object)
|
| + return false;
|
| +
|
| + int prime_fd = -1;
|
| + drm_intel_bo_gem_export_to_prime(buffer_object, &prime_fd);
|
| + drm_intel_bo_unreference(buffer_object);
|
| + *handle = base::FileDescriptor(prime_fd, true);
|
| + return true;
|
| +}
|
| +
|
| +bool GpuMemoryBufferImplIntelDRM::Initialize(
|
| + gfx::GpuMemoryBufferHandle handle) {
|
| + TRACE_EVENT0("gpu", "GpuMemoryBufferImplIntelDRM::Initialize");
|
| +
|
| + if (!IsHandleValid(handle.handle))
|
| + return false;
|
| +
|
| + // Note: Ownership is passed with |handle|. This requires us to close the file
|
| + // descriptor before returning from this function when initialization fails.
|
| + base::ScopedFD prime_fd(handle.handle.fd);
|
| +
|
| + DCHECK(!buffer_object_);
|
| + buffer_object_ =
|
| + g_buffer_object_factory.Pointer()->CreateBufferObjectFromPrimeFd(
|
| + size_, internalformat_, prime_fd.get());
|
| + if (!buffer_object_)
|
| + return false;
|
| +
|
| + prime_fd_.swap(prime_fd);
|
| + return true;
|
| +}
|
| +
|
| +bool GpuMemoryBufferImplIntelDRM::InitializeFromBufferObject(
|
| + drm_intel_bo* buffer_object) {
|
| + DCHECK(!buffer_object_);
|
| + buffer_object_ = buffer_object;
|
| +
|
| + int prime_fd = -1;
|
| + drm_intel_bo_gem_export_to_prime(buffer_object_, &prime_fd);
|
| + prime_fd_.reset(prime_fd);
|
| + return true;
|
| +}
|
| +
|
| +void* GpuMemoryBufferImplIntelDRM::Map(AccessMode mode) {
|
| + TRACE_EVENT0("gpu", "GpuMemoryBufferImplIntelDRM::Map");
|
| +
|
| + DCHECK(!mapped_);
|
| + DCHECK(buffer_object_);
|
| + drm_intel_bo_map(buffer_object_, WriteEnable(mode));
|
| + mapped_ = true;
|
| + return buffer_object_->virt;
|
| +}
|
| +
|
| +void GpuMemoryBufferImplIntelDRM::Unmap() {
|
| + TRACE_EVENT0("gpu", "GpuMemoryBufferImplIntelDRM::Unmap");
|
| +
|
| + DCHECK(mapped_);
|
| + drm_intel_bo_unmap(buffer_object_);
|
| + mapped_ = false;
|
| +}
|
| +
|
| +uint32 GpuMemoryBufferImplIntelDRM::GetStride() const {
|
| + return BufferObjectStride(size_, internalformat_);
|
| +}
|
| +
|
| +gfx::GpuMemoryBufferHandle GpuMemoryBufferImplIntelDRM::GetHandle() const {
|
| + gfx::GpuMemoryBufferHandle handle;
|
| + handle.type = gfx::INTEL_DRM_BUFFER;
|
| + handle.handle = base::FileDescriptor(prime_fd_.get(), true);
|
| + return handle;
|
| +}
|
| +
|
| +} // namespace content
|
|
|