Ozone support for multiprocess graphics. VgemPixmap allows scanout of gem handle imported by file descriptor. Change-Id: I233b3992f2289754c904da94f98d4707cd227d0d BUG= R=cstout@chromium.org Review URL: https://codereview.chromium.org/1582613004 .
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn index 4044d81..922e4bd 100644 --- a/ui/gfx/BUILD.gn +++ b/ui/gfx/BUILD.gn
@@ -127,6 +127,10 @@ ] } + if (use_ozone) { + sources += [ "native_pixmap_handle_ozone.h" ] + } + if (use_x11) { deps += [ "//ui/gfx/x" ] }
diff --git a/ui/gfx/native_pixmap_handle_ozone.h b/ui/gfx/native_pixmap_handle_ozone.h new file mode 100644 index 0000000..14d5560 --- /dev/null +++ b/ui/gfx/native_pixmap_handle_ozone.h
@@ -0,0 +1,22 @@ +// 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. + +#ifndef UI_GFX_NATIVE_PIXMAP_HANDLE_OZONE_H_ +#define UI_GFX_NATIVE_PIXMAP_HANDLE_OZONE_H_ + +#include "base/file_descriptor_posix.h" + +namespace gfx { + +struct NativePixmapHandle { + // A file descriptor for the underlying memory object (usually dmabuf). + base::FileDescriptor fd; + + // The stride to used when accessing the buffer via a memory mapping. + int32_t stride = 0; +}; + +} // namespace gfx + +#endif // UI_GFX_NATIVE_PIXMAP_HANDLE_OZONE_H_
diff --git a/ui/ozone/platform/drm/BUILD.gn b/ui/ozone/platform/drm/BUILD.gn index 7333ad2..7c93434 100644 --- a/ui/ozone/platform/drm/BUILD.gn +++ b/ui/ozone/platform/drm/BUILD.gn
@@ -116,13 +116,13 @@ deps = [ "//base", - "//skia", "//mojo/application", "//mojo/common", "//mojo/converters/geometry", "//mojo/converters/ozone_drm_gpu", "//mojo/services/ozone_drm_gpu/interfaces", "//mojo/services/ozone_drm_host/interfaces", + "//skia", "//ui/base", "//ui/display/types", "//ui/display/util", @@ -154,10 +154,10 @@ "//base", "//skia", "//ui/base", - "//ui/ozone:ozone_base", "//ui/events/ozone:events_ozone", "//ui/events/ozone:events_ozone_evdev", "//ui/events/ozone:events_ozone_layout", + "//ui/ozone:ozone_base", ] } } @@ -196,6 +196,8 @@ source_set("gbm") { sources = [ + "gpu/drm_dmabuf_pixmap.cc", + "gpu/drm_dmabuf_pixmap.h", "gpu/gbm_buffer.cc", "gpu/gbm_buffer.h", "gpu/gbm_buffer_base.cc",
diff --git a/ui/ozone/platform/drm/gpu/drm_device.cc b/ui/ozone/platform/drm/gpu/drm_device.cc index 1d80b68..7ec92a4 100644 --- a/ui/ozone/platform/drm/gpu/drm_device.cc +++ b/ui/ozone/platform/drm/gpu/drm_device.cc
@@ -5,6 +5,7 @@ #include "ui/ozone/platform/drm/gpu/drm_device.h" #include <fcntl.h> +#include <i915_drm.h> #include <sys/mman.h> #include <unistd.h> #include <xf86drm.h> @@ -615,4 +616,42 @@ &g[0], &b[0]) == 0); } +bool DrmDevice::BufferHandleToFd(uint32_t handle, int* fd) { + int ret; + + ret = drmPrimeHandleToFD(file_.GetPlatformFile(), handle, DRM_CLOEXEC, fd); + if (ret == -1) + return false; + + return true; +} + +bool DrmDevice::BufferFdToHandle(int fd, uint32_t* handle) { + int ret; + + ret = drmPrimeFDToHandle(file_.GetPlatformFile(), fd, handle); + if (ret == -1) + return false; + + return true; +} + +bool DrmDevice::BufferHandleSetTiling(uint32_t handle, + uint32_t stride, + uint32_t tiling_mode) { + struct drm_i915_gem_set_tiling set_tiling; + int ret; + + do { + set_tiling.handle = handle; + set_tiling.tiling_mode = tiling_mode; + set_tiling.stride = stride; + + ret = drmIoctl(file_.GetPlatformFile(), DRM_IOCTL_I915_GEM_SET_TILING, + &set_tiling); + } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + + return ret != -1; +} + } // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_device.h b/ui/ozone/platform/drm/gpu/drm_device.h index 012dde7..21d98d2 100644 --- a/ui/ozone/platform/drm/gpu/drm_device.h +++ b/ui/ozone/platform/drm/gpu/drm_device.h
@@ -178,6 +178,12 @@ HardwareDisplayPlaneManager* plane_manager() { return plane_manager_.get(); } + bool BufferHandleToFd(uint32_t handle, int* fd); + bool BufferFdToHandle(int fd, uint32_t* handle); + bool BufferHandleSetTiling(uint32_t handle, + uint32_t stride, + uint32_t tiling_mode); + protected: friend class base::RefCountedThreadSafe<DrmDevice>;
diff --git a/ui/ozone/platform/drm/gpu/drm_dmabuf_pixmap.cc b/ui/ozone/platform/drm/gpu/drm_dmabuf_pixmap.cc new file mode 100644 index 0000000..338e75a --- /dev/null +++ b/ui/ozone/platform/drm/gpu/drm_dmabuf_pixmap.cc
@@ -0,0 +1,110 @@ +// 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/drm_dmabuf_pixmap.h" + +#include <i915_drm.h> +#include "base/logging.h" +#include "ui/ozone/platform/drm/gpu/drm_device.h" +#include "ui/ozone/platform/drm/gpu/drm_window.h" + +namespace ui { + +namespace { +void EmptyPageFlipCallback(gfx::SwapResult result) {} +} // namespace + +DrmDmabufPixmap::DrmDmabufPixmap(const scoped_refptr<DrmDevice>& drm) + : drm_(drm) {} + +DrmDmabufPixmap::~DrmDmabufPixmap() { + // TODO: finish + if (framebuffer_ && !drm_->RemoveFramebuffer(framebuffer_)) + PLOG(ERROR) << "SharedBuffer: RemoveFramebuffer: fb " << framebuffer_; +} + +bool DrmDmabufPixmap::Initialize(base::ScopedFD dma_buf, + int width, + int height, + uint32_t pitch) { + int fd = dma_buf.get(); + if (!drm_->BufferFdToHandle(fd, &handle_)) { + PLOG(ERROR) << "SharedBuffer: Initialize: couldn't get handle from fd " + << fd; + return false; + } + + // For scanout + if (!drm_->BufferHandleSetTiling(handle_, pitch, I915_TILING_X)) + return false; + + dma_buf_ = dma_buf.Pass(); + dma_buf_pitch_ = pitch; + + width_ = width; + height_ = height; + + if (!drm_->AddFramebuffer(width_, height_, 24, 32, dma_buf_pitch_, handle_, + &framebuffer_)) { + PLOG(ERROR) << "SharedBuffer: AddFramebuffer: handle " << handle_; + return false; + } + + return true; +} + +uint32_t DrmDmabufPixmap::GetHandle() const { + return handle_; +} + +gfx::Size DrmDmabufPixmap::GetSize() const { + return gfx::Size(width_, height_); +} + +uint32_t DrmDmabufPixmap::GetFramebufferId() const { + return framebuffer_; +} + +int DrmDmabufPixmap::GetDmaBufFd() const { + return dma_buf_.get(); +} + +int DrmDmabufPixmap::GetDmaBufPitch() const { + return dma_buf_pitch_; +} + +DrmDmabufPixmapWrapper::DrmDmabufPixmapWrapper( + ScreenManager* screen_manager, + const scoped_refptr<DrmDmabufPixmap>& pixmap) + : pixmap_(pixmap), screen_manager_(screen_manager) {} + +DrmDmabufPixmapWrapper::~DrmDmabufPixmapWrapper() {} + +bool DrmDmabufPixmapWrapper::ScheduleOverlayPlane( + gfx::AcceleratedWidget widget, + int plane_z_order, + gfx::OverlayTransform plane_transform, + const gfx::Rect& display_bounds, + const gfx::RectF& crop_rect) { + screen_manager_->GetWindow(widget)->QueueOverlayPlane(OverlayPlane(pixmap_)); + // TODO(cstout): for the multi-overlay case, SchedulePageFlip should be called + // once after all overlay planes are scheduled. Tracking issue mojo #540. + screen_manager_->GetWindow(widget)->SchedulePageFlip( + true /* is_sync */, base::Bind(&EmptyPageFlipCallback)); + return true; +} + +int DrmDmabufPixmapWrapper::GetDmaBufFd() { + return pixmap_->GetDmaBufFd(); +} + +int DrmDmabufPixmapWrapper::GetDmaBufPitch() { + return pixmap_->GetDmaBufPitch(); +} + +void* DrmDmabufPixmapWrapper::GetEGLClientBuffer() { + return nullptr; +} + +} // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_dmabuf_pixmap.h b/ui/ozone/platform/drm/gpu/drm_dmabuf_pixmap.h new file mode 100644 index 0000000..c3d29de --- /dev/null +++ b/ui/ozone/platform/drm/gpu/drm_dmabuf_pixmap.h
@@ -0,0 +1,79 @@ +// 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. + +#ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_DMABUF_PIXMAP_H_ +#define UI_OZONE_PLATFORM_DRM_GPU_DRM_DMABUF_PIXMAP_H_ + +#include "base/files/scoped_file.h" +#include "base/macros.h" +#include "ui/ozone/platform/drm/gpu/scanout_buffer.h" +#include "ui/ozone/platform/drm/gpu/screen_manager.h" +#include "ui/ozone/public/native_pixmap.h" + +namespace ui { + +class DrmDevice; + +// DrmDmabufPixmap is a reference to a dmabuf file descriptor. +// 'Pixmap' not 'buffer' because we have a size (width and height). +class DrmDmabufPixmap : public ScanoutBuffer { + public: + DrmDmabufPixmap(const scoped_refptr<DrmDevice>& drm); + ~DrmDmabufPixmap() override; + + bool Initialize(base::ScopedFD dma_buf, + int width, + int height, + uint32_t pitch); + + // ScanoutBuffer: + uint32_t GetFramebufferId() const override; + uint32_t GetHandle() const override; + gfx::Size GetSize() const override; + + int GetDmaBufFd() const; + int GetDmaBufPitch() const; + + private: + scoped_refptr<DrmDevice> drm_; + + // PRIME file descriptor. + base::ScopedFD dma_buf_; + uint32_t dma_buf_pitch_ = -1; + + // Local gem handle for the file descriptior. + uint32_t handle_ = 0; + + // Framebuffer ID for scanout. + uint32_t framebuffer_ = 0; + + int width_ = 0; + int height_ = 0; +}; + +class DrmDmabufPixmapWrapper : public NativePixmap { + public: + DrmDmabufPixmapWrapper(ScreenManager* screen_manager, + const scoped_refptr<DrmDmabufPixmap>& pixmap); + ~DrmDmabufPixmapWrapper() override; + + // NativePixmap + void* /* EGLClientBuffer */ GetEGLClientBuffer() override; + int GetDmaBufFd() override; + int GetDmaBufPitch() override; + + bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget, + int plane_z_order, + gfx::OverlayTransform plane_transform, + const gfx::Rect& display_bounds, + const gfx::RectF& crop_rect) override; + + private: + scoped_refptr<DrmDmabufPixmap> pixmap_; + ScreenManager* screen_manager_; +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_DRM_GPU_DRM_DMABUF_PIXMAP_H_
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc index 93e7793..80a9b1f 100644 --- a/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc +++ b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
@@ -10,6 +10,7 @@ #include "third_party/khronos/EGL/egl.h" #include "ui/ozone/common/egl_util.h" #include "ui/ozone/platform/drm/gpu/drm_device_manager.h" +#include "ui/ozone/platform/drm/gpu/drm_dmabuf_pixmap.h" #include "ui/ozone/platform/drm/gpu/drm_window.h" #include "ui/ozone/platform/drm/gpu/gbm_buffer.h" #include "ui/ozone/platform/drm/gpu/gbm_device.h" @@ -130,6 +131,22 @@ return pixmap; } +scoped_refptr<ui::NativePixmap> GbmSurfaceFactory::CreateNativePixmapFromHandle( + gfx::AcceleratedWidget widget, + gfx::Size size, + const gfx::NativePixmapHandle& handle) { + scoped_refptr<DrmDevice> drm = + drm_device_manager_->GetDrmDevice(widget).get(); + DCHECK(drm); + + scoped_refptr<VgemPixmap> pixmap(new VgemPixmap(drm)); + pixmap->Initialize(base::ScopedFD(handle.fd.fd), size.width(), size.height(), + handle.stride); + + return scoped_refptr<VgemPixmapWrapper>( + new VgemPixmapWrapper(screen_manager_, pixmap)); +} + bool GbmSurfaceFactory::CanShowPrimaryPlaneAsOverlay() { DCHECK(thread_checker_.CalledOnValidThread()); return allow_surfaceless_;
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface_factory.h b/ui/ozone/platform/drm/gpu/gbm_surface_factory.h index 0bc01b3..b3b6676 100644 --- a/ui/ozone/platform/drm/gpu/gbm_surface_factory.h +++ b/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
@@ -39,6 +39,10 @@ gfx::Size size, BufferFormat format, BufferUsage usage) override; + scoped_refptr<ui::NativePixmap> CreateNativePixmapFromHandle( + gfx::AcceleratedWidget widget, + gfx::Size size, + const gfx::NativePixmapHandle& handle) override; bool CanShowPrimaryPlaneAsOverlay() override; bool CanCreateNativePixmap(BufferUsage usage) override;
diff --git a/ui/ozone/public/surface_factory_ozone.cc b/ui/ozone/public/surface_factory_ozone.cc index 70a81ad..42f44ca 100644 --- a/ui/ozone/public/surface_factory_ozone.cc +++ b/ui/ozone/public/surface_factory_ozone.cc
@@ -52,7 +52,15 @@ gfx::Size size, BufferFormat format, BufferUsage usage) { - return NULL; + return nullptr; +} + +scoped_refptr<ui::NativePixmap> +SurfaceFactoryOzone::CreateNativePixmapFromHandle( + gfx::AcceleratedWidget widget, + gfx::Size size, + const gfx::NativePixmapHandle& handle) { + return nullptr; } bool SurfaceFactoryOzone::CanShowPrimaryPlaneAsOverlay() {
diff --git a/ui/ozone/public/surface_factory_ozone.h b/ui/ozone/public/surface_factory_ozone.h index 4dc5572..4a72f3f 100644 --- a/ui/ozone/public/surface_factory_ozone.h +++ b/ui/ozone/public/surface_factory_ozone.h
@@ -9,9 +9,11 @@ #include "base/memory/scoped_ptr.h" #include "base/native_library.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/native_pixmap_handle_ozone.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/overlay_transform.h" #include "ui/ozone/ozone_base_export.h" +#include "ui/ozone/public/native_pixmap.h" namespace ui { @@ -121,6 +123,13 @@ BufferFormat format, BufferUsage usage); + // Create a single native buffer from an existing handle. Takes ownership of + // |handle| and can be called on any thread. + virtual scoped_refptr<NativePixmap> CreateNativePixmapFromHandle( + gfx::AcceleratedWidget widget, + gfx::Size size, + const gfx::NativePixmapHandle& handle); + // Returns true if overlays can be shown at z-index 0, replacing the main // surface. Combined with surfaceless extensions, it allows for an // overlay-only mode.