| 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 bool IsHandleValid(const base::FileDescriptor& handle) { | 
|  | 86   return handle.fd >= 0; | 
|  | 87 } | 
|  | 88 | 
|  | 89 // Aligns 'value' by rounding it up to the next multiple of 'alignment' | 
|  | 90 uint64 AlignValue(uint64 value, int alignment) { | 
|  | 91   return value + (alignment - (value % alignment)) % alignment; | 
|  | 92 } | 
|  | 93 | 
|  | 94 uint64 BufferObjectStride(gfx::Size size, unsigned internalformat) { | 
|  | 95   uint64 stride = static_cast<uint64>(size.width()) * | 
|  | 96                   GpuMemoryBufferImpl::BytesPerPixel(internalformat); | 
|  | 97 | 
|  | 98   // Note: Intel DRM API doesn't provide an interface that allows us to compute | 
|  | 99   // or query the stride. This should match the driver when untiled. | 
|  | 100   return AlignValue(stride, 64); | 
|  | 101 } | 
|  | 102 | 
|  | 103 class BufferObjectFactory { | 
|  | 104  public: | 
|  | 105   BufferObjectFactory() : buffer_manager_(NULL) { | 
|  | 106     std::string dev_name( | 
|  | 107         base::StringPrintf(DRM_DEV_NAME, DRM_DIR_NAME, kDeviceId)); | 
|  | 108     base::ScopedFD dri_fd(open(dev_name.c_str(), O_RDWR)); | 
|  | 109     if (dri_fd.get() < 0) { | 
|  | 110       LOG(ERROR) << "Failed to open: " << dev_name; | 
|  | 111       return; | 
|  | 112     } | 
|  | 113 | 
|  | 114 #if defined(USE_X11) | 
|  | 115     drm_magic_t magic; | 
|  | 116     if (drmGetMagic(dri_fd.get(), &magic)) | 
|  | 117       return; | 
|  | 118 | 
|  | 119     if (!X11DRI2Authenticate(magic)) { | 
|  | 120       LOG(ERROR) << "DRI2Authenticate failed."; | 
|  | 121       return; | 
|  | 122     } | 
|  | 123 #endif | 
|  | 124 | 
|  | 125     buffer_manager_ = drm_intel_bufmgr_gem_init(dri_fd.get(), kBatchSize); | 
|  | 126     if (!buffer_manager_) { | 
|  | 127       LOG(ERROR) << "drm_intel_bufmgr_gem_init failed."; | 
|  | 128       return; | 
|  | 129     } | 
|  | 130 | 
|  | 131     dri_fd_.swap(dri_fd); | 
|  | 132   } | 
|  | 133   ~BufferObjectFactory() { | 
|  | 134     if (buffer_manager_) | 
|  | 135       drm_intel_bufmgr_destroy(buffer_manager_); | 
|  | 136   } | 
|  | 137 | 
|  | 138   drm_intel_bo* CreateBufferObject(gfx::Size size, unsigned internalformat) { | 
|  | 139     DCHECK(thread_checker_.CalledOnValidThread()); | 
|  | 140 | 
|  | 141     if (!buffer_manager_) | 
|  | 142       return NULL; | 
|  | 143 | 
|  | 144     uint64 expected_stride = BufferObjectStride(size, internalformat); | 
|  | 145     if (!base::IsValueInRangeForNumericType<uint32>(expected_stride)) | 
|  | 146       return NULL; | 
|  | 147 | 
|  | 148     uint32_t tiling_mode = I915_TILING_NONE; | 
|  | 149     unsigned long stride = 0; | 
|  | 150     drm_intel_bo* buffer_object = drm_intel_bo_alloc_tiled( | 
|  | 151         buffer_manager_, | 
|  | 152         "chromium-gpu-memory-buffer", | 
|  | 153         size.width(), | 
|  | 154         size.height(), | 
|  | 155         GpuMemoryBufferImpl::BytesPerPixel(internalformat), | 
|  | 156         &tiling_mode, | 
|  | 157         &stride, | 
|  | 158         0); | 
|  | 159     if (!buffer_object) { | 
|  | 160       LOG(ERROR) << "drm_intel_bo_alloc_tiled failed."; | 
|  | 161       return NULL; | 
|  | 162     } | 
|  | 163 | 
|  | 164     // This might fail if the stride computed by BufferObjectStride() doesn't | 
|  | 165     // match that of the driver. | 
|  | 166     if (static_cast<uint64>(stride) != expected_stride) { | 
|  | 167       LOG(ERROR) << "Unexpected stride: " << stride << " vs " | 
|  | 168                  << expected_stride; | 
|  | 169       drm_intel_bo_unreference(buffer_object); | 
|  | 170       return NULL; | 
|  | 171     } | 
|  | 172 | 
|  | 173     return buffer_object; | 
|  | 174   } | 
|  | 175 | 
|  | 176   drm_intel_bo* CreateBufferObjectFromPrimeFd(gfx::Size size, | 
|  | 177                                               unsigned internalformat, | 
|  | 178                                               int prime_fd) { | 
|  | 179     DCHECK(thread_checker_.CalledOnValidThread()); | 
|  | 180 | 
|  | 181     if (!buffer_manager_) | 
|  | 182       return NULL; | 
|  | 183 | 
|  | 184     uint64 stride = BufferObjectStride(size, internalformat); | 
|  | 185     if (!base::IsValueInRangeForNumericType<uint32>(stride)) | 
|  | 186       return NULL; | 
|  | 187 | 
|  | 188     uint64 buffer_size = stride * size.height(); | 
|  | 189     if (!base::IsValueInRangeForNumericType<int>(buffer_size)) | 
|  | 190       return NULL; | 
|  | 191 | 
|  | 192     return drm_intel_bo_gem_create_from_prime( | 
|  | 193         buffer_manager_, prime_fd, buffer_size); | 
|  | 194   } | 
|  | 195 | 
|  | 196  private: | 
|  | 197   base::ThreadChecker thread_checker_; | 
|  | 198   base::ScopedFD dri_fd_; | 
|  | 199   drm_intel_bufmgr* buffer_manager_; | 
|  | 200 }; | 
|  | 201 base::LazyInstance<BufferObjectFactory>::Leaky g_buffer_object_factory = | 
|  | 202     LAZY_INSTANCE_INITIALIZER; | 
|  | 203 | 
|  | 204 }  // namespace | 
|  | 205 | 
|  | 206 GpuMemoryBufferImplIntelDRM::GpuMemoryBufferImplIntelDRM( | 
|  | 207     gfx::Size size, | 
|  | 208     unsigned internalformat) | 
|  | 209     : GpuMemoryBufferImpl(size, internalformat), buffer_object_(NULL) {} | 
|  | 210 | 
|  | 211 GpuMemoryBufferImplIntelDRM::~GpuMemoryBufferImplIntelDRM() { | 
|  | 212   if (buffer_object_) | 
|  | 213     drm_intel_bo_unreference(buffer_object_); | 
|  | 214 } | 
|  | 215 | 
|  | 216 // static | 
|  | 217 bool GpuMemoryBufferImplIntelDRM::IsFormatSupported(unsigned internalformat) { | 
|  | 218   switch (internalformat) { | 
|  | 219     case GL_BGRA8_EXT: | 
|  | 220       return true; | 
|  | 221     default: | 
|  | 222       return false; | 
|  | 223   } | 
|  | 224 } | 
|  | 225 | 
|  | 226 // static | 
|  | 227 drm_intel_bo* GpuMemoryBufferImplIntelDRM::CreateBufferObject( | 
|  | 228     gfx::Size size, | 
|  | 229     unsigned internalformat) { | 
|  | 230   return g_buffer_object_factory.Pointer()->CreateBufferObject(size, | 
|  | 231                                                                internalformat); | 
|  | 232 } | 
|  | 233 | 
|  | 234 // static | 
|  | 235 bool GpuMemoryBufferImplIntelDRM::AllocateBufferObject( | 
|  | 236     gfx::Size size, | 
|  | 237     unsigned internalformat, | 
|  | 238     base::SharedMemoryHandle* handle) { | 
|  | 239   drm_intel_bo* buffer_object = CreateBufferObject(size, internalformat); | 
|  | 240   if (!buffer_object) | 
|  | 241     return false; | 
|  | 242 | 
|  | 243   int prime_fd = -1; | 
|  | 244   drm_intel_bo_gem_export_to_prime(buffer_object, &prime_fd); | 
|  | 245   drm_intel_bo_unreference(buffer_object); | 
|  | 246   *handle = base::FileDescriptor(prime_fd, true); | 
|  | 247   return true; | 
|  | 248 } | 
|  | 249 | 
|  | 250 bool GpuMemoryBufferImplIntelDRM::Initialize( | 
|  | 251     gfx::GpuMemoryBufferHandle handle) { | 
|  | 252   TRACE_EVENT0("gpu", "GpuMemoryBufferImplIntelDRM::Initialize"); | 
|  | 253 | 
|  | 254   if (!IsHandleValid(handle.handle)) | 
|  | 255     return false; | 
|  | 256 | 
|  | 257   // Note: Ownership is passed with |handle|. This requires us to close the file | 
|  | 258   // descriptor before returning from this function when initialization fails. | 
|  | 259   base::ScopedFD prime_fd(handle.handle.fd); | 
|  | 260 | 
|  | 261   DCHECK(!buffer_object_); | 
|  | 262   buffer_object_ = | 
|  | 263       g_buffer_object_factory.Pointer()->CreateBufferObjectFromPrimeFd( | 
|  | 264           size_, internalformat_, prime_fd.get()); | 
|  | 265   if (!buffer_object_) | 
|  | 266     return false; | 
|  | 267 | 
|  | 268   prime_fd_.swap(prime_fd); | 
|  | 269   return true; | 
|  | 270 } | 
|  | 271 | 
|  | 272 bool GpuMemoryBufferImplIntelDRM::InitializeFromBufferObject( | 
|  | 273     drm_intel_bo* buffer_object) { | 
|  | 274   DCHECK(!buffer_object_); | 
|  | 275   buffer_object_ = buffer_object; | 
|  | 276 | 
|  | 277   int prime_fd = -1; | 
|  | 278   drm_intel_bo_gem_export_to_prime(buffer_object_, &prime_fd); | 
|  | 279   prime_fd_.reset(prime_fd); | 
|  | 280   return true; | 
|  | 281 } | 
|  | 282 | 
|  | 283 void* GpuMemoryBufferImplIntelDRM::Map() { | 
|  | 284   TRACE_EVENT0("gpu", "GpuMemoryBufferImplIntelDRM::Map"); | 
|  | 285 | 
|  | 286   DCHECK(!mapped_); | 
|  | 287   DCHECK(buffer_object_); | 
|  | 288   drm_intel_bo_map(buffer_object_, 1); | 
|  | 289   mapped_ = true; | 
|  | 290   return buffer_object_->virt; | 
|  | 291 } | 
|  | 292 | 
|  | 293 void GpuMemoryBufferImplIntelDRM::Unmap() { | 
|  | 294   TRACE_EVENT0("gpu", "GpuMemoryBufferImplIntelDRM::Unmap"); | 
|  | 295 | 
|  | 296   DCHECK(mapped_); | 
|  | 297   drm_intel_bo_unmap(buffer_object_); | 
|  | 298   mapped_ = false; | 
|  | 299 } | 
|  | 300 | 
|  | 301 uint32 GpuMemoryBufferImplIntelDRM::GetStride() const { | 
|  | 302   return BufferObjectStride(size_, internalformat_); | 
|  | 303 } | 
|  | 304 | 
|  | 305 gfx::GpuMemoryBufferHandle GpuMemoryBufferImplIntelDRM::GetHandle() const { | 
|  | 306   gfx::GpuMemoryBufferHandle handle; | 
|  | 307   handle.type = gfx::INTEL_DRM_BUFFER; | 
|  | 308   handle.handle = base::FileDescriptor(prime_fd_.get(), true); | 
|  | 309   return handle; | 
|  | 310 } | 
|  | 311 | 
|  | 312 }  // namespace content | 
| OLD | NEW | 
|---|