Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/common/gpu/client/gpu_memory_buffer_impl_ozone_gbm.h" | |
| 6 | |
| 7 #include <fcntl.h> | |
| 8 #include <sys/mman.h> | |
| 9 #include <xf86drm.h> | |
| 10 | |
| 11 #include "base/lazy_instance.h" | |
| 12 #include "base/threading/thread_local.h" | |
| 13 #include "base/trace_event/trace_event.h" | |
| 14 | |
| 15 namespace content { | |
| 16 | |
| 17 namespace { | |
| 18 | |
| 19 class VGemDevice { | |
| 20 public: | |
| 21 VGemDevice(); | |
| 22 ~VGemDevice(); | |
| 23 bool Initialize(const base::FileDescriptor& device_fd); | |
| 24 int device_fd() const; | |
| 25 | |
| 26 private: | |
| 27 base::ScopedFD device_fd_; | |
| 28 base::ThreadChecker thread_checker_; | |
| 29 | |
| 30 DISALLOW_COPY_AND_ASSIGN(VGemDevice); | |
| 31 }; | |
| 32 | |
| 33 VGemDevice::VGemDevice() { | |
| 34 } | |
| 35 | |
| 36 VGemDevice::~VGemDevice() { | |
| 37 } | |
| 38 | |
| 39 bool VGemDevice::Initialize(const base::FileDescriptor& device_fd) { | |
| 40 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 41 if (device_fd_.get() > 0) | |
| 42 return true; | |
| 43 | |
| 44 DCHECK(device_fd.auto_close); | |
| 45 device_fd_.reset(device_fd.fd); | |
| 46 return true; | |
| 47 } | |
| 48 | |
| 49 int VGemDevice::device_fd() const { | |
| 50 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 51 return device_fd_.get(); | |
| 52 } | |
| 53 | |
| 54 // --single-process launches a render thread instead of a render process, so | |
| 55 // use ThreadLocalPointer to keep vgem fd per renderer. | |
| 56 base::LazyInstance<base::ThreadLocalPointer<VGemDevice>>::Leaky g_vgem_device = | |
| 57 LAZY_INSTANCE_INITIALIZER; | |
| 58 | |
| 59 } // namespace | |
| 60 | |
| 61 GpuMemoryBufferImplOzoneGbm::GpuMemoryBufferImplOzoneGbm( | |
| 62 gfx::GpuMemoryBufferId id, | |
| 63 const gfx::Size& size, | |
| 64 Format format, | |
| 65 const DestructionCallback& callback) | |
| 66 : GpuMemoryBufferImplOzoneNativeBuffer(id, size, format, callback), | |
| 67 vgem_bo_handle_(0), | |
| 68 stride_(0), | |
| 69 mmap_ptr_(nullptr) { | |
| 70 RowSizeInBytes(size_.width(), format_, 0, &stride_); | |
| 71 } | |
| 72 | |
| 73 GpuMemoryBufferImplOzoneGbm::~GpuMemoryBufferImplOzoneGbm() { | |
| 74 if (vgem_bo_handle_) { | |
| 75 // TODO(dshwang): Both causes CRASH. How to release a handle? | |
| 76 if (false) { | |
| 77 struct drm_mode_destroy_dumb destroy; | |
| 78 memset(&destroy, 0, sizeof(destroy)); | |
| 79 destroy.handle = vgem_bo_handle_; | |
| 80 int ret = drmIoctl(g_vgem_device.Pointer()->Get()->device_fd(), | |
| 81 DRM_IOCTL_MODE_DESTROY_DUMB, &destroy); | |
| 82 if (!ret) | |
| 83 LOG(ERROR) << "fail to free a vgem buffer. error:" << ret; | |
| 84 } | |
| 85 if (false) { | |
| 86 struct drm_gem_close close; | |
| 87 memset(&close, 0, sizeof(close)); | |
| 88 close.handle = vgem_bo_handle_; | |
| 89 int ret = drmIoctl(g_vgem_device.Pointer()->Get()->device_fd(), | |
| 90 DRM_IOCTL_GEM_CLOSE, &close); | |
| 91 if (!ret) | |
| 92 LOG(ERROR) << "fail to free a vgem buffer. error:" << ret; | |
| 93 } | |
|
dshwang
2015/05/11 13:38:05
zachr, I could not release the handle because both
| |
| 94 vgem_bo_handle_ = 0; | |
| 95 } | |
| 96 } | |
| 97 | |
| 98 // static | |
| 99 scoped_ptr<GpuMemoryBufferImpl> GpuMemoryBufferImplOzoneGbm::CreateFromHandle( | |
| 100 const gfx::GpuMemoryBufferHandle& handle, | |
| 101 const gfx::Size& size, | |
| 102 Format format, | |
| 103 const DestructionCallback& callback) { | |
| 104 scoped_ptr<GpuMemoryBufferImplOzoneGbm> buffer = make_scoped_ptr( | |
| 105 new GpuMemoryBufferImplOzoneGbm(handle.id, size, format, callback)); | |
| 106 if (!buffer->Initialize(handle)) | |
| 107 return nullptr; | |
| 108 return buffer.Pass(); | |
| 109 } | |
| 110 | |
| 111 bool GpuMemoryBufferImplOzoneGbm::Initialize( | |
| 112 const gfx::GpuMemoryBufferHandle& handle) { | |
| 113 // Render process must close |device_handle|. | |
| 114 DCHECK(handle.device_handle.auto_close); | |
| 115 if (!g_vgem_device.Pointer()->Get()) { | |
| 116 g_vgem_device.Pointer()->Set(new VGemDevice); | |
| 117 g_vgem_device.Pointer()->Get()->Initialize(handle.device_handle); | |
| 118 } else { | |
| 119 // TODO(dshwang): pass this fd only one time for each render process. | |
| 120 base::ScopedFD closing_fd(handle.device_handle.fd); | |
| 121 } | |
| 122 DCHECK(g_vgem_device.Pointer()->Get()->device_fd()); | |
| 123 | |
| 124 DCHECK(handle.handle.auto_close); | |
| 125 dma_buf_.reset(handle.handle.fd); | |
| 126 | |
| 127 int ret = drmPrimeFDToHandle(g_vgem_device.Pointer()->Get()->device_fd(), | |
| 128 dma_buf_.get(), &vgem_bo_handle_); | |
| 129 if (ret) { | |
| 130 LOG(ERROR) << "drmPrimeFDToHandle failed, handle:" << vgem_bo_handle_; | |
| 131 return false; | |
| 132 } | |
| 133 return true; | |
| 134 } | |
| 135 | |
| 136 bool GpuMemoryBufferImplOzoneGbm::Map(void** data) { | |
| 137 TRACE_EVENT0("gpu", "GpuMemoryBufferImplOzoneGbm::Map"); | |
| 138 DCHECK(!mapped_); | |
| 139 DCHECK(!mmap_ptr_); | |
| 140 DCHECK(vgem_bo_handle_); | |
| 141 | |
| 142 struct drm_mode_map_dumb mmap_arg; | |
| 143 memset(&mmap_arg, 0, sizeof(mmap_arg)); | |
| 144 mmap_arg.handle = vgem_bo_handle_; | |
| 145 | |
| 146 int ret = drmIoctl(g_vgem_device.Pointer()->Get()->device_fd(), | |
| 147 DRM_IOCTL_MODE_MAP_DUMB, &mmap_arg); | |
| 148 if (ret) { | |
| 149 LOG(ERROR) << "fail to map a vgem buffer. error:" << ret; | |
| 150 return false; | |
| 151 } | |
| 152 DCHECK(mmap_arg.offset); | |
| 153 | |
| 154 size_t size = stride_ * size_.height(); | |
| 155 mmap_ptr_ = | |
| 156 mmap(nullptr, size, (PROT_READ | PROT_WRITE), MAP_SHARED, | |
| 157 g_vgem_device.Pointer()->Get()->device_fd(), mmap_arg.offset); | |
| 158 DCHECK(mmap_ptr_ != MAP_FAILED); | |
| 159 mapped_ = true; | |
| 160 *data = mmap_ptr_; | |
| 161 return true; | |
| 162 } | |
| 163 | |
| 164 void GpuMemoryBufferImplOzoneGbm::Unmap() { | |
| 165 TRACE_EVENT0("gpu", "GpuMemoryBufferImplOzoneGbm::Unmap"); | |
| 166 DCHECK(mapped_); | |
| 167 DCHECK(mmap_ptr_); | |
| 168 size_t size = stride_ * size_.height(); | |
| 169 int ret = munmap(mmap_ptr_, size); | |
| 170 DCHECK(!ret); | |
| 171 mmap_ptr_ = nullptr; | |
| 172 mapped_ = false; | |
| 173 } | |
| 174 | |
| 175 void GpuMemoryBufferImplOzoneGbm::GetStride(int* stride) const { | |
| 176 *stride = stride_; | |
| 177 } | |
| 178 | |
| 179 gfx::GpuMemoryBufferHandle GpuMemoryBufferImplOzoneGbm::GetHandle() const { | |
| 180 // Don't need to set |handle.handle| and |handle.device_handle| because gpu | |
| 181 // process can look up the right pixmap only by id. | |
| 182 // See ui::GpuMemoryBufferFactoryOzoneNativeBuffer | |
| 183 return GpuMemoryBufferImplOzoneNativeBuffer::GetHandle(); | |
| 184 } | |
| 185 | |
| 186 } // namespace content | |
| OLD | NEW |