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..5be46571ed3bc2e3ee07385248c1f92c1eb0d104 |
--- /dev/null |
+++ b/content/common/gpu/client/gpu_memory_buffer_impl_intel_drm.cc |
@@ -0,0 +1,297 @@ |
+// 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; |
+} |
+ |
+void ExportBufferObject(drm_intel_bo* buffer_object, |
+ base::SharedMemoryHandle* handle) { |
+ int prime_fd = -1; |
+ drm_intel_bo_gem_export_to_prime(buffer_object, &prime_fd); |
+ *handle = base::FileDescriptor(prime_fd, true); |
+} |
+ |
+uint64 BufferObjectPitch(gfx::Size size, unsigned internalformat) { |
+ return static_cast<uint64>(size.width()) * |
+ GpuMemoryBufferImpl::BytesPerPixel(internalformat); |
+} |
+ |
+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_pitch = BufferObjectPitch(size, internalformat); |
+ if (!base::IsValueInRangeForNumericType<uint32>(expected_pitch)) |
+ return NULL; |
+ |
+ uint32_t tiling_mode = I915_TILING_NONE; |
+ unsigned long pitch = 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, |
+ &pitch, |
+ 0); |
+ if (!buffer_object) { |
+ LOG(ERROR) << "drm_intel_bo_alloc_tiled failed."; |
+ return NULL; |
+ } |
+ |
+ // |pitch| must match what we expect. |
+ if (static_cast<uint64>(pitch) != expected_pitch) { |
+ LOG(ERROR) << "Unexpected pitch: " << pitch << " vs " << expected_pitch; |
+ 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 pitch = BufferObjectPitch(size, internalformat); |
+ if (!base::IsValueInRangeForNumericType<uint32>(pitch)) |
+ return NULL; |
+ |
+ uint64 buffer_size = pitch * 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; |
+ |
+ ExportBufferObject(buffer_object, handle); |
+ drm_intel_bo_unreference(buffer_object); |
+ return true; |
+} |
+ |
+bool GpuMemoryBufferImplIntelDRM::Initialize( |
+ gfx::GpuMemoryBufferHandle handle) { |
+ TRACE_EVENT0("gpu", "GpuMemoryBufferImplIntelDRM::Initialize"); |
+ |
+ DCHECK(!buffer_object_); |
+ buffer_object_ = |
+ g_buffer_object_factory.Pointer()->CreateBufferObjectFromPrimeFd( |
+ size_, internalformat_, handle.handle.fd); |
+ return !!buffer_object_; |
+} |
+ |
+bool GpuMemoryBufferImplIntelDRM::InitializeFromBufferObject( |
+ drm_intel_bo* buffer_object) { |
+ DCHECK(!buffer_object_); |
+ buffer_object_ = buffer_object; |
+ 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; |
+} |
+ |
+gfx::GpuMemoryBufferHandle GpuMemoryBufferImplIntelDRM::GetHandle() const { |
+ gfx::GpuMemoryBufferHandle handle; |
+ handle.type = gfx::INTEL_DRM_BUFFER; |
+ DCHECK(buffer_object_); |
+ ExportBufferObject(buffer_object_, &handle.handle); |
fjhenigman
2014/04/11 02:45:28
GetHandle() should cache the result of drm_intel_b
reveman
2014/04/11 05:54:27
Done.
|
+ return handle; |
+} |
+ |
+} // namespace content |