OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 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_intel_drm.h" |
| 6 |
| 7 extern "C" { |
| 8 #include <fcntl.h> |
| 9 #include <libdrm/i915_drm.h> |
| 10 #include <libdrm/intel_bufmgr.h> |
| 11 #include <xf86drm.h> |
| 12 #if defined(USE_X11) |
| 13 #include <X11/Xlib.h> |
| 14 #include <X11/Xlibint.h> |
| 15 #include <X11/extensions/Xext.h> |
| 16 #include <X11/extensions/extutil.h> |
| 17 #include <X11/extensions/dri2proto.h> |
| 18 // X11/Xlibint.h define min/max macros which will conflict with std::min/max |
| 19 // unless we undefine them here. |
| 20 #undef min |
| 21 #undef max |
| 22 #endif |
| 23 } |
| 24 |
| 25 #include "base/debug/trace_event.h" |
| 26 #include "base/files/scoped_file.h" |
| 27 #include "base/lazy_instance.h" |
| 28 #include "base/logging.h" |
| 29 #include "base/numerics/safe_conversions.h" |
| 30 #include "base/strings/stringprintf.h" |
| 31 #include "base/threading/thread_checker.h" |
| 32 #include "ui/gl/gl_bindings.h" |
| 33 |
| 34 #if defined(USE_X11) |
| 35 #include "ui/gfx/x/x11_types.h" |
| 36 #endif |
| 37 |
| 38 namespace content { |
| 39 namespace { |
| 40 |
| 41 #if defined(USE_X11) |
| 42 static char g_dri2_extension_name[] = DRI2_NAME; |
| 43 static XExtensionInfo* g_dri2_info; |
| 44 static XExtensionHooks g_dri2_extension_hooks = {NULL, // create_gc |
| 45 NULL, // copy_gc |
| 46 NULL, // flush_gc |
| 47 NULL, // free_gc |
| 48 NULL, // create_font |
| 49 NULL, // free_font |
| 50 NULL, // close_display |
| 51 NULL, // wire_to_event |
| 52 NULL, // event_to_wire |
| 53 NULL, // error |
| 54 NULL, // error_string |
| 55 }; |
| 56 static XEXT_GENERATE_FIND_DISPLAY(DRI2FindDisplay, |
| 57 g_dri2_info, |
| 58 g_dri2_extension_name, |
| 59 &g_dri2_extension_hooks, |
| 60 0, |
| 61 NULL); |
| 62 |
| 63 bool X11DRI2Authenticate(drm_magic_t magic) { |
| 64 Display* dpy = gfx::GetXDisplay(); |
| 65 XExtDisplayInfo* info = DRI2FindDisplay(dpy); |
| 66 XextCheckExtension(dpy, info, g_dri2_extension_name, false); |
| 67 LockDisplay(dpy); |
| 68 xDRI2AuthenticateReq* req; |
| 69 GetReq(DRI2Authenticate, req); |
| 70 req->reqType = info->codes->major_opcode; |
| 71 req->dri2ReqType = X_DRI2Authenticate; |
| 72 req->window = DefaultRootWindow(dpy); |
| 73 req->magic = magic; |
| 74 xDRI2AuthenticateReply rep; |
| 75 int status = _XReply(dpy, reinterpret_cast<xReply*>(&rep), 0, xFalse); |
| 76 UnlockDisplay(dpy); |
| 77 SyncHandle(); |
| 78 return status && rep.authenticated; |
| 79 } |
| 80 #endif // USE_X11 |
| 81 |
| 82 const int kDeviceId = 0; |
| 83 const int kBatchSize = 2048; |
| 84 |
| 85 int WriteEnable(gfx::GpuMemoryBuffer::AccessMode mode) { |
| 86 switch (mode) { |
| 87 case gfx::GpuMemoryBuffer::READ_ONLY: |
| 88 return 0; |
| 89 case gfx::GpuMemoryBuffer::WRITE_ONLY: |
| 90 case gfx::GpuMemoryBuffer::READ_WRITE: |
| 91 return 1; |
| 92 } |
| 93 |
| 94 NOTREACHED(); |
| 95 return 0; |
| 96 } |
| 97 |
| 98 bool IsHandleValid(const base::FileDescriptor& handle) { |
| 99 return handle.fd >= 0; |
| 100 } |
| 101 |
| 102 // Aligns 'value' by rounding it up to the next multiple of 'alignment' |
| 103 uint64 AlignValue(uint64 value, int alignment) { |
| 104 return value + (alignment - (value % alignment)) % alignment; |
| 105 } |
| 106 |
| 107 uint64 BufferObjectStride(gfx::Size size, unsigned internalformat) { |
| 108 uint64 stride = static_cast<uint64>(size.width()) * |
| 109 GpuMemoryBufferImpl::BytesPerPixel(internalformat); |
| 110 |
| 111 // Note: Intel DRM API doesn't provide an interface that allows us to compute |
| 112 // or query the stride. This should match the driver when untiled. |
| 113 return AlignValue(stride, 64); |
| 114 } |
| 115 |
| 116 class BufferObjectFactory { |
| 117 public: |
| 118 BufferObjectFactory() : buffer_manager_(NULL) { |
| 119 std::string dev_name( |
| 120 base::StringPrintf(DRM_DEV_NAME, DRM_DIR_NAME, kDeviceId)); |
| 121 base::ScopedFD dri_fd(open(dev_name.c_str(), O_RDWR)); |
| 122 if (dri_fd.get() < 0) { |
| 123 LOG(ERROR) << "Failed to open: " << dev_name; |
| 124 return; |
| 125 } |
| 126 |
| 127 #if defined(USE_X11) |
| 128 drm_magic_t magic; |
| 129 if (drmGetMagic(dri_fd.get(), &magic)) |
| 130 return; |
| 131 |
| 132 if (!X11DRI2Authenticate(magic)) { |
| 133 LOG(ERROR) << "DRI2Authenticate failed."; |
| 134 return; |
| 135 } |
| 136 #endif |
| 137 |
| 138 buffer_manager_ = drm_intel_bufmgr_gem_init(dri_fd.get(), kBatchSize); |
| 139 if (!buffer_manager_) { |
| 140 LOG(ERROR) << "drm_intel_bufmgr_gem_init failed."; |
| 141 return; |
| 142 } |
| 143 |
| 144 dri_fd_.swap(dri_fd); |
| 145 } |
| 146 ~BufferObjectFactory() { |
| 147 if (buffer_manager_) |
| 148 drm_intel_bufmgr_destroy(buffer_manager_); |
| 149 } |
| 150 |
| 151 drm_intel_bo* CreateBufferObject(gfx::Size size, unsigned internalformat) { |
| 152 DCHECK(thread_checker_.CalledOnValidThread()); |
| 153 |
| 154 if (!buffer_manager_) |
| 155 return NULL; |
| 156 |
| 157 uint64 expected_stride = BufferObjectStride(size, internalformat); |
| 158 if (!base::IsValueInRangeForNumericType<uint32>(expected_stride)) |
| 159 return NULL; |
| 160 |
| 161 uint32_t tiling_mode = I915_TILING_NONE; |
| 162 unsigned long stride = 0; |
| 163 drm_intel_bo* buffer_object = drm_intel_bo_alloc_tiled( |
| 164 buffer_manager_, |
| 165 "chromium-gpu-memory-buffer", |
| 166 size.width(), |
| 167 size.height(), |
| 168 GpuMemoryBufferImpl::BytesPerPixel(internalformat), |
| 169 &tiling_mode, |
| 170 &stride, |
| 171 0); |
| 172 if (!buffer_object) { |
| 173 LOG(ERROR) << "drm_intel_bo_alloc_tiled failed."; |
| 174 return NULL; |
| 175 } |
| 176 |
| 177 // This might fail if the stride computed by BufferObjectStride() doesn't |
| 178 // match that of the driver. |
| 179 if (static_cast<uint64>(stride) != expected_stride) { |
| 180 LOG(ERROR) << "Unexpected stride: " << stride << " vs " |
| 181 << expected_stride; |
| 182 drm_intel_bo_unreference(buffer_object); |
| 183 return NULL; |
| 184 } |
| 185 |
| 186 return buffer_object; |
| 187 } |
| 188 |
| 189 drm_intel_bo* CreateBufferObjectFromPrimeFd(gfx::Size size, |
| 190 unsigned internalformat, |
| 191 int prime_fd) { |
| 192 DCHECK(thread_checker_.CalledOnValidThread()); |
| 193 |
| 194 if (!buffer_manager_) |
| 195 return NULL; |
| 196 |
| 197 uint64 stride = BufferObjectStride(size, internalformat); |
| 198 if (!base::IsValueInRangeForNumericType<uint32>(stride)) |
| 199 return NULL; |
| 200 |
| 201 uint64 buffer_size = stride * size.height(); |
| 202 if (!base::IsValueInRangeForNumericType<int>(buffer_size)) |
| 203 return NULL; |
| 204 |
| 205 return drm_intel_bo_gem_create_from_prime( |
| 206 buffer_manager_, prime_fd, buffer_size); |
| 207 } |
| 208 |
| 209 private: |
| 210 base::ThreadChecker thread_checker_; |
| 211 base::ScopedFD dri_fd_; |
| 212 drm_intel_bufmgr* buffer_manager_; |
| 213 }; |
| 214 base::LazyInstance<BufferObjectFactory>::Leaky g_buffer_object_factory = |
| 215 LAZY_INSTANCE_INITIALIZER; |
| 216 |
| 217 } // namespace |
| 218 |
| 219 GpuMemoryBufferImplIntelDRM::GpuMemoryBufferImplIntelDRM( |
| 220 gfx::Size size, |
| 221 unsigned internalformat) |
| 222 : GpuMemoryBufferImpl(size, internalformat), buffer_object_(NULL) {} |
| 223 |
| 224 GpuMemoryBufferImplIntelDRM::~GpuMemoryBufferImplIntelDRM() { |
| 225 if (buffer_object_) |
| 226 drm_intel_bo_unreference(buffer_object_); |
| 227 } |
| 228 |
| 229 // static |
| 230 bool GpuMemoryBufferImplIntelDRM::IsFormatSupported(unsigned internalformat) { |
| 231 switch (internalformat) { |
| 232 case GL_BGRA8_EXT: |
| 233 return true; |
| 234 default: |
| 235 return false; |
| 236 } |
| 237 } |
| 238 |
| 239 // static |
| 240 drm_intel_bo* GpuMemoryBufferImplIntelDRM::CreateBufferObject( |
| 241 gfx::Size size, |
| 242 unsigned internalformat) { |
| 243 return g_buffer_object_factory.Pointer()->CreateBufferObject(size, |
| 244 internalformat); |
| 245 } |
| 246 |
| 247 // static |
| 248 bool GpuMemoryBufferImplIntelDRM::AllocateBufferObject( |
| 249 gfx::Size size, |
| 250 unsigned internalformat, |
| 251 base::SharedMemoryHandle* handle) { |
| 252 drm_intel_bo* buffer_object = CreateBufferObject(size, internalformat); |
| 253 if (!buffer_object) |
| 254 return false; |
| 255 |
| 256 int prime_fd = -1; |
| 257 drm_intel_bo_gem_export_to_prime(buffer_object, &prime_fd); |
| 258 drm_intel_bo_unreference(buffer_object); |
| 259 *handle = base::FileDescriptor(prime_fd, true); |
| 260 return true; |
| 261 } |
| 262 |
| 263 bool GpuMemoryBufferImplIntelDRM::Initialize( |
| 264 gfx::GpuMemoryBufferHandle handle) { |
| 265 TRACE_EVENT0("gpu", "GpuMemoryBufferImplIntelDRM::Initialize"); |
| 266 |
| 267 if (!IsHandleValid(handle.handle)) |
| 268 return false; |
| 269 |
| 270 // Note: Ownership is passed with |handle|. This requires us to close the file |
| 271 // descriptor before returning from this function when initialization fails. |
| 272 base::ScopedFD prime_fd(handle.handle.fd); |
| 273 |
| 274 DCHECK(!buffer_object_); |
| 275 buffer_object_ = |
| 276 g_buffer_object_factory.Pointer()->CreateBufferObjectFromPrimeFd( |
| 277 size_, internalformat_, prime_fd.get()); |
| 278 if (!buffer_object_) |
| 279 return false; |
| 280 |
| 281 prime_fd_.swap(prime_fd); |
| 282 return true; |
| 283 } |
| 284 |
| 285 bool GpuMemoryBufferImplIntelDRM::InitializeFromBufferObject( |
| 286 drm_intel_bo* buffer_object) { |
| 287 DCHECK(!buffer_object_); |
| 288 buffer_object_ = buffer_object; |
| 289 |
| 290 int prime_fd = -1; |
| 291 drm_intel_bo_gem_export_to_prime(buffer_object_, &prime_fd); |
| 292 prime_fd_.reset(prime_fd); |
| 293 return true; |
| 294 } |
| 295 |
| 296 void* GpuMemoryBufferImplIntelDRM::Map(AccessMode mode) { |
| 297 TRACE_EVENT0("gpu", "GpuMemoryBufferImplIntelDRM::Map"); |
| 298 |
| 299 DCHECK(!mapped_); |
| 300 DCHECK(buffer_object_); |
| 301 drm_intel_bo_map(buffer_object_, WriteEnable(mode)); |
| 302 mapped_ = true; |
| 303 return buffer_object_->virt; |
| 304 } |
| 305 |
| 306 void GpuMemoryBufferImplIntelDRM::Unmap() { |
| 307 TRACE_EVENT0("gpu", "GpuMemoryBufferImplIntelDRM::Unmap"); |
| 308 |
| 309 DCHECK(mapped_); |
| 310 drm_intel_bo_unmap(buffer_object_); |
| 311 mapped_ = false; |
| 312 } |
| 313 |
| 314 uint32 GpuMemoryBufferImplIntelDRM::GetStride() const { |
| 315 return BufferObjectStride(size_, internalformat_); |
| 316 } |
| 317 |
| 318 gfx::GpuMemoryBufferHandle GpuMemoryBufferImplIntelDRM::GetHandle() const { |
| 319 gfx::GpuMemoryBufferHandle handle; |
| 320 handle.type = gfx::INTEL_DRM_BUFFER; |
| 321 handle.handle = base::FileDescriptor(prime_fd_.get(), true); |
| 322 return handle; |
| 323 } |
| 324 |
| 325 } // namespace content |
OLD | NEW |