Chromium Code Reviews| 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/strings/stringprintf.h" | |
| 30 #include "base/threading/thread_checker.h" | |
| 31 #include "ui/gl/gl_bindings.h" | |
| 32 | |
| 33 #if defined(USE_X11) | |
| 34 #include "ui/gfx/x/x11_types.h" | |
| 35 #endif | |
| 36 | |
| 37 namespace content { | |
| 38 namespace { | |
| 39 | |
| 40 #if defined(USE_X11) | |
| 41 static char g_dri2_extension_name[] = DRI2_NAME; | |
| 42 static XExtensionInfo* g_dri2_info; | |
| 43 static XExtensionHooks g_dri2_extension_hooks = {NULL, // create_gc | |
| 44 NULL, // copy_gc | |
| 45 NULL, // flush_gc | |
| 46 NULL, // free_gc | |
| 47 NULL, // create_font | |
| 48 NULL, // free_font | |
| 49 NULL, // close_display | |
| 50 NULL, // wire_to_event | |
| 51 NULL, // event_to_wire | |
| 52 NULL, // error | |
| 53 NULL, // error_string | |
| 54 }; | |
| 55 static XEXT_GENERATE_FIND_DISPLAY(DRI2FindDisplay, | |
| 56 g_dri2_info, | |
| 57 g_dri2_extension_name, | |
| 58 &g_dri2_extension_hooks, | |
| 59 0, | |
| 60 NULL); | |
| 61 | |
| 62 bool X11DRI2Authenticate(drm_magic_t magic) { | |
| 63 Display* dpy = gfx::GetXDisplay(); | |
| 64 XExtDisplayInfo* info = DRI2FindDisplay(dpy); | |
| 65 XextCheckExtension(dpy, info, g_dri2_extension_name, false); | |
| 66 LockDisplay(dpy); | |
| 67 xDRI2AuthenticateReq* req; | |
| 68 GetReq(DRI2Authenticate, req); | |
| 69 req->reqType = info->codes->major_opcode; | |
| 70 req->dri2ReqType = X_DRI2Authenticate; | |
| 71 req->window = DefaultRootWindow(dpy); | |
| 72 req->magic = magic; | |
| 73 xDRI2AuthenticateReply rep; | |
| 74 int status = _XReply(dpy, reinterpret_cast<xReply*>(&rep), 0, xFalse); | |
| 75 UnlockDisplay(dpy); | |
| 76 SyncHandle(); | |
| 77 return status && rep.authenticated; | |
| 78 } | |
| 79 #endif // USE_X11 | |
| 80 | |
| 81 const int kDeviceId = 0; | |
| 82 const int kBatchSize = 2048; | |
| 83 | |
| 84 int WriteEnable(gfx::GpuMemoryBuffer::AccessMode mode) { | |
| 85 switch (mode) { | |
| 86 case gfx::GpuMemoryBuffer::READ_ONLY: | |
| 87 return 0; | |
| 88 case gfx::GpuMemoryBuffer::WRITE_ONLY: | |
| 89 case gfx::GpuMemoryBuffer::READ_WRITE: | |
| 90 return 1; | |
| 91 } | |
| 92 | |
| 93 NOTREACHED(); | |
| 94 return 0; | |
| 95 } | |
| 96 | |
| 97 void ExportBufferObject(drm_intel_bo* buffer_object, | |
| 98 base::SharedMemoryHandle* handle) { | |
| 99 int prime_fd = -1; | |
| 100 drm_intel_bo_gem_export_to_prime(buffer_object, &prime_fd); | |
| 101 *handle = base::FileDescriptor(prime_fd, true); | |
| 102 } | |
| 103 | |
| 104 uint64 BufferObjectPitch(gfx::Size size, unsigned internalformat) { | |
| 105 return static_cast<uint64>(size.width()) * | |
| 106 GpuMemoryBufferImpl::BytesPerPixel(internalformat); | |
| 107 } | |
| 108 | |
| 109 class BufferObjectFactory { | |
| 110 public: | |
| 111 BufferObjectFactory() : buffer_manager_(NULL) { | |
| 112 std::string dev_name( | |
| 113 base::StringPrintf(DRM_DEV_NAME, DRM_DIR_NAME, kDeviceId)); | |
| 114 base::ScopedFD dri_fd(open(dev_name.c_str(), O_RDWR)); | |
| 115 if (dri_fd.get() < 0) { | |
| 116 LOG(ERROR) << "Failed to open: " << dev_name; | |
| 117 return; | |
| 118 } | |
| 119 | |
| 120 #if defined(USE_X11) | |
| 121 drm_magic_t magic; | |
| 122 if (drmGetMagic(dri_fd.get(), &magic)) | |
| 123 return; | |
| 124 | |
| 125 if (!X11DRI2Authenticate(magic)) { | |
| 126 LOG(ERROR) << "DRI2Authenticate failed."; | |
| 127 return; | |
| 128 } | |
| 129 #endif | |
| 130 | |
| 131 buffer_manager_ = drm_intel_bufmgr_gem_init(dri_fd.get(), kBatchSize); | |
| 132 if (!buffer_manager_) | |
| 133 LOG(ERROR) << "drm_intel_bufmgr_gem_init failed."; | |
| 134 } | |
| 135 ~BufferObjectFactory() { | |
| 136 if (buffer_manager_) | |
| 137 drm_intel_bufmgr_destroy(buffer_manager_); | |
| 138 } | |
| 139 | |
| 140 drm_intel_bo* CreateBufferObject(gfx::Size size, unsigned internalformat) { | |
| 141 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 142 | |
| 143 if (!buffer_manager_) | |
| 144 return NULL; | |
| 145 | |
| 146 uint64 expected_pitch = BufferObjectPitch(size, internalformat); | |
| 147 if (expected_pitch > std::numeric_limits<uint32>::max()) | |
| 148 return NULL; | |
| 149 | |
| 150 uint32_t tiling_mode = I915_TILING_NONE; | |
| 151 unsigned long pitch = 0; | |
| 152 drm_intel_bo* buffer_object = drm_intel_bo_alloc_tiled( | |
| 153 buffer_manager_, | |
| 154 "ChromiumGpuMemoryBuffer", | |
| 155 size.width(), | |
| 156 size.height(), | |
| 157 GpuMemoryBufferImpl::BytesPerPixel(internalformat), | |
| 158 &tiling_mode, | |
| 159 &pitch, | |
| 160 0); | |
| 161 if (!buffer_object) { | |
| 162 LOG(ERROR) << "drm_intel_bo_alloc_tiled failed."; | |
| 163 return NULL; | |
| 164 } | |
| 165 | |
| 166 // |pitch| must match what we expect. | |
| 167 if (static_cast<uint64>(pitch) != expected_pitch) { | |
| 168 LOG(ERROR) << "Unexpected pitch: " << pitch << " vs " << expected_pitch; | |
| 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 pitch = BufferObjectPitch(size, internalformat); | |
| 185 if (pitch > std::numeric_limits<uint32>::max()) | |
| 186 return NULL; | |
| 187 | |
| 188 uint64 buffer_size = pitch * size.height(); | |
| 189 if (buffer_size > std::numeric_limits<int32>::max()) | |
|
fjhenigman
2014/04/09 16:33:52
should be uint32
reveman
2014/04/09 18:22:22
Fixed by using base::IsValueInRangeForNumericType
| |
| 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 drm_intel_bufmgr* buffer_manager_; | |
| 199 }; | |
| 200 base::LazyInstance<BufferObjectFactory>::Leaky g_buffer_object_factory = | |
| 201 LAZY_INSTANCE_INITIALIZER; | |
| 202 | |
| 203 } // namespace | |
| 204 | |
| 205 GpuMemoryBufferImplIntelDRM::GpuMemoryBufferImplIntelDRM( | |
| 206 gfx::Size size, | |
| 207 unsigned internalformat) | |
| 208 : GpuMemoryBufferImpl(size, internalformat), buffer_object_(NULL) {} | |
| 209 | |
| 210 GpuMemoryBufferImplIntelDRM::~GpuMemoryBufferImplIntelDRM() { | |
| 211 if (buffer_object_) | |
| 212 drm_intel_bo_unreference(buffer_object_); | |
| 213 } | |
| 214 | |
| 215 // static | |
| 216 bool GpuMemoryBufferImplIntelDRM::IsFormatSupported(unsigned internalformat) { | |
| 217 switch (internalformat) { | |
| 218 case GL_BGRA8_EXT: | |
| 219 return true; | |
| 220 default: | |
| 221 return false; | |
| 222 } | |
| 223 } | |
| 224 | |
| 225 // static | |
| 226 drm_intel_bo* GpuMemoryBufferImplIntelDRM::CreateBufferObject( | |
| 227 gfx::Size size, | |
| 228 unsigned internalformat) { | |
| 229 return g_buffer_object_factory.Pointer()->CreateBufferObject(size, | |
| 230 internalformat); | |
| 231 } | |
| 232 | |
| 233 // static | |
| 234 bool GpuMemoryBufferImplIntelDRM::AllocateBufferObject( | |
| 235 gfx::Size size, | |
| 236 unsigned internalformat, | |
| 237 base::SharedMemoryHandle* handle) { | |
| 238 drm_intel_bo* buffer_object = CreateBufferObject(size, internalformat); | |
| 239 if (!buffer_object) | |
| 240 return false; | |
| 241 | |
| 242 ExportBufferObject(buffer_object, handle); | |
| 243 drm_intel_bo_unreference(buffer_object); | |
| 244 return true; | |
| 245 } | |
| 246 | |
| 247 bool GpuMemoryBufferImplIntelDRM::Initialize( | |
| 248 gfx::GpuMemoryBufferHandle handle) { | |
| 249 TRACE_EVENT0("gpu", "GpuMemoryBufferImplIntelDRM::Initialize"); | |
| 250 | |
| 251 DCHECK(!buffer_object_); | |
| 252 buffer_object_ = | |
| 253 g_buffer_object_factory.Pointer()->CreateBufferObjectFromPrimeFd( | |
| 254 size_, internalformat_, handle.handle.fd); | |
| 255 return !!buffer_object_; | |
| 256 } | |
| 257 | |
| 258 bool GpuMemoryBufferImplIntelDRM::InitializeFromBufferObject( | |
| 259 drm_intel_bo* buffer_object) { | |
| 260 DCHECK(!buffer_object_); | |
| 261 buffer_object_ = buffer_object; | |
| 262 return true; | |
| 263 } | |
| 264 | |
| 265 void* GpuMemoryBufferImplIntelDRM::Map(AccessMode mode) { | |
| 266 TRACE_EVENT0("gpu", "GpuMemoryBufferImplIntelDRM::Map"); | |
| 267 | |
| 268 DCHECK(!mapped_); | |
| 269 DCHECK(buffer_object_); | |
| 270 drm_intel_bo_map(buffer_object_, WriteEnable(mode)); | |
| 271 mapped_ = true; | |
| 272 return buffer_object_->virt; | |
| 273 } | |
| 274 | |
| 275 void GpuMemoryBufferImplIntelDRM::Unmap() { | |
| 276 TRACE_EVENT0("gpu", "GpuMemoryBufferImplIntelDRM::Unmap"); | |
| 277 | |
| 278 DCHECK(mapped_); | |
| 279 drm_intel_bo_unmap(buffer_object_); | |
| 280 mapped_ = false; | |
| 281 } | |
| 282 | |
| 283 gfx::GpuMemoryBufferHandle GpuMemoryBufferImplIntelDRM::GetHandle() const { | |
| 284 gfx::GpuMemoryBufferHandle handle; | |
| 285 handle.type = gfx::INTEL_DRM_BUFFER; | |
| 286 DCHECK(buffer_object_); | |
| 287 ExportBufferObject(buffer_object_, &handle.handle); | |
| 288 return handle; | |
| 289 } | |
| 290 | |
| 291 } // namespace content | |
| OLD | NEW |