Index: ui/ozone/platform/drm/gpu/gbm_map_pixmap_intel.cc |
diff --git a/ui/ozone/platform/drm/gpu/gbm_map_pixmap_intel.cc b/ui/ozone/platform/drm/gpu/gbm_map_pixmap_intel.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3166e7dc03c1c96c3a819c4b5f6cbb112c96a625 |
--- /dev/null |
+++ b/ui/ozone/platform/drm/gpu/gbm_map_pixmap_intel.cc |
@@ -0,0 +1,168 @@ |
+// Copyright 2015 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/gpu/gbm_map_pixmap_intel.h" |
+ |
+#include <libdrm/i915_drm.h> |
+ |
+#include "base/lazy_instance.h" |
+#include "base/numerics/safe_math.h" |
+#include "base/trace_event/trace_event.h" |
+#include "ui/ozone/platform/drm/gpu/gbm_device.h" |
+#include "ui/ozone/public/platform/drm_intel_buffer_manager.h" |
+ |
+namespace ui { |
+ |
+namespace { |
+ |
+int BytesPerPixel(SurfaceFactoryOzone::BufferFormat format) { |
+ switch (format) { |
+ case SurfaceFactoryOzone::BGRA_8888: |
+ case SurfaceFactoryOzone::RGBX_8888: |
+ return 4; |
+ default: |
+ NOTREACHED(); |
+ return 0; |
+ } |
+} |
+ |
+unsigned long StrideInBytes(int width, |
+ SurfaceFactoryOzone::BufferFormat format) { |
+ base::CheckedNumeric<unsigned long> s = width; |
+ switch (format) { |
+ case SurfaceFactoryOzone::BGRA_8888: |
+ case SurfaceFactoryOzone::RGBX_8888: |
+ s *= BytesPerPixel(format); |
+ DCHECK(s.IsValid()); |
+ return s.ValueOrDie(); |
+ default: |
+ NOTREACHED(); |
+ return 0; |
+ } |
+} |
+ |
+bool ShareToRenderProcess(int prime_fd, base::FileDescriptor* new_handle) { |
+ const int new_fd = dup(prime_fd); |
+ if (new_fd < 0) { |
+ DPLOG(ERROR) << "dup() failed."; |
+ return false; |
+ } |
+ |
+ *new_handle = base::FileDescriptor(new_fd, true); |
+ return true; |
+} |
+ |
+base::LazyInstance<DrmIntelBufferManager>::Leaky g_buffer_manager = |
+ LAZY_INSTANCE_INITIALIZER; |
+ |
+} // namespace |
+ |
+// static |
+scoped_refptr<GbmMapPixmapIntel> GbmMapPixmapIntel::CreatePixmap( |
+ const scoped_refptr<GbmDevice>& gbm, |
+ SurfaceFactoryOzone::BufferFormat format, |
+ const gfx::Size& size, |
+ gfx::GpuMemoryBufferHandle* handle) { |
+ TRACE_EVENT2("drm", "GbmMapPixmapIntel::CreatePixmap", "device", |
+ gbm->device_path().value(), "size", size.ToString()); |
+ |
+ scoped_refptr<GbmMapPixmapIntel> pixmap(new GbmMapPixmapIntel()); |
+ if (!pixmap->Initialize(gbm, format, size, handle)) |
+ return nullptr; |
+ |
+ return pixmap; |
+} |
+ |
+GbmMapPixmapIntel::GbmMapPixmapIntel() : buffer_(nullptr), stride_(0) { |
+} |
+ |
+bool GbmMapPixmapIntel::Initialize(const scoped_refptr<GbmDevice>& gbm, |
+ SurfaceFactoryOzone::BufferFormat format, |
+ const gfx::Size& size, |
+ gfx::GpuMemoryBufferHandle* handle) { |
+ DCHECK(handle); |
+ if (!g_buffer_manager.Pointer()->buffer_manager()) { |
+ g_buffer_manager.Pointer()->Initialize( |
+ base::FileDescriptor(gbm->get_fd(), false)); |
+ } else { |
+ DCHECK(g_buffer_manager.Pointer()->device_fd() == gbm->get_fd()); |
+ } |
+ |
+ unsigned long expected_stride = StrideInBytes(size.width(), format); |
+ uint32_t tiling_mode = I915_TILING_NONE; |
+ unsigned long stride = 0; |
+ buffer_ = drm_intel_bo_alloc_tiled( |
+ g_buffer_manager.Pointer()->buffer_manager(), |
+ "chromium-gpu-memory-buffer", size.width(), size.height(), |
+ BytesPerPixel(format), &tiling_mode, &stride, 0); |
+ if (!buffer_) { |
+ DLOG(ERROR) << "drm_intel_bo_alloc_tiled failed."; |
+ return false; |
+ } |
+ |
+ // It's possible that StrideInBytes() doesn't match that of the driver. |
+ // It's why it sends |stride| to render process. |
+ if (stride != expected_stride) { |
+ DLOG(WARNING) << "Unexpected stride: " << stride << " vs " |
+ << expected_stride; |
+ } |
+ DCHECK(stride); |
+ stride_ = stride; |
+ handle->stride = stride_; |
+ |
+ int prime_fd = -1; |
+ drm_intel_bo_gem_export_to_prime(buffer_, &prime_fd); |
+ if (prime_fd <= 0) { |
+ DLOG(ERROR) << "Fail to export a drm buffer file descriptor"; |
+ return false; |
+ } |
+ prime_fd_.reset(prime_fd); |
+ base::FileDescriptor dup_handle; |
+ if (!ShareToRenderProcess(prime_fd_.get(), &dup_handle)) { |
+ DLOG(ERROR) << "Fail to duplicate a drm buffer file descriptor"; |
+ return false; |
+ } |
+ |
+ base::FileDescriptor dup_device_handle; |
+ if (!ShareToRenderProcess(gbm->get_fd(), &dup_device_handle)) { |
+ base::ScopedFD fd(dup_handle.fd); |
+ DLOG(ERROR) << "Fail to duplicate a drm file descriptor"; |
+ return false; |
+ } |
+ |
+ handle->handle = dup_handle; |
+ // TODO(dshwang): pass |device_handle| only one time to each render process. |
+ handle->device_handle = dup_device_handle; |
+ return true; |
+} |
+ |
+GbmMapPixmapIntel::~GbmMapPixmapIntel() { |
+ if (buffer_) { |
+ // TODO(dshwang): It can fix glitch and crash bugs for Ozone GBM |
+ // This is called after bound texture and bound EGLImage are deleted, |
+ // but causes GPU Process crash in mesa with this log |
+ // "drm intel crash: intel_do_flush_locked failed: Invalid argument" |
+ // After drm_intel_bo_unreference() is called, sometime later, mesa causes |
+ // crash, but gdb cannot catch stack trace. I guess crash happens in |
+ // mesa internal thread. |
+ // Surprisingly, glFinish in ResourceProvider::DeleteResourceInternal() |
+ // fixes this issue also. see ResourceProvider |
+ // drm_intel_bo_unreference(buffer_); |
dshwang
2015/04/09 19:12:26
As comment said, this CL has glitch and crash bugs
|
+ buffer_ = nullptr; |
+ } |
+} |
+ |
+void* GbmMapPixmapIntel::GetEGLClientBuffer() { |
+ return nullptr; |
+} |
+ |
+int GbmMapPixmapIntel::GetDmaBufFd() { |
+ return prime_fd_.get(); |
+} |
+ |
+int GbmMapPixmapIntel::GetDmaBufPitch() { |
+ return stride_; |
+} |
+ |
+} // namespace ui |