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 void ExportBufferObject(drm_intel_bo* buffer_object, | |
99 base::SharedMemoryHandle* handle) { | |
100 int prime_fd = -1; | |
101 drm_intel_bo_gem_export_to_prime(buffer_object, &prime_fd); | |
102 *handle = base::FileDescriptor(prime_fd, true); | |
103 } | |
104 | |
105 uint64 BufferObjectPitch(gfx::Size size, unsigned internalformat) { | |
106 return static_cast<uint64>(size.width()) * | |
107 GpuMemoryBufferImpl::BytesPerPixel(internalformat); | |
108 } | |
109 | |
110 class BufferObjectFactory { | |
111 public: | |
112 BufferObjectFactory() : buffer_manager_(NULL) { | |
113 std::string dev_name( | |
114 base::StringPrintf(DRM_DEV_NAME, DRM_DIR_NAME, kDeviceId)); | |
115 base::ScopedFD dri_fd(open(dev_name.c_str(), O_RDWR)); | |
116 if (dri_fd.get() < 0) { | |
117 LOG(ERROR) << "Failed to open: " << dev_name; | |
118 return; | |
119 } | |
120 | |
121 #if defined(USE_X11) | |
122 drm_magic_t magic; | |
123 if (drmGetMagic(dri_fd.get(), &magic)) | |
124 return; | |
125 | |
126 if (!X11DRI2Authenticate(magic)) { | |
127 LOG(ERROR) << "DRI2Authenticate failed."; | |
128 return; | |
129 } | |
130 #endif | |
131 | |
132 buffer_manager_ = drm_intel_bufmgr_gem_init(dri_fd.get(), kBatchSize); | |
133 if (!buffer_manager_) { | |
134 LOG(ERROR) << "drm_intel_bufmgr_gem_init failed."; | |
135 return; | |
136 } | |
137 | |
138 dri_fd_.swap(dri_fd); | |
139 } | |
140 ~BufferObjectFactory() { | |
141 if (buffer_manager_) | |
142 drm_intel_bufmgr_destroy(buffer_manager_); | |
143 } | |
144 | |
145 drm_intel_bo* CreateBufferObject(gfx::Size size, unsigned internalformat) { | |
146 DCHECK(thread_checker_.CalledOnValidThread()); | |
147 | |
148 if (!buffer_manager_) | |
149 return NULL; | |
150 | |
151 uint64 expected_pitch = BufferObjectPitch(size, internalformat); | |
152 if (!base::IsValueInRangeForNumericType<uint32>(expected_pitch)) | |
153 return NULL; | |
154 | |
155 uint32_t tiling_mode = I915_TILING_NONE; | |
156 unsigned long pitch = 0; | |
157 drm_intel_bo* buffer_object = drm_intel_bo_alloc_tiled( | |
158 buffer_manager_, | |
159 "chromium-gpu-memory-buffer", | |
160 size.width(), | |
161 size.height(), | |
162 GpuMemoryBufferImpl::BytesPerPixel(internalformat), | |
163 &tiling_mode, | |
164 &pitch, | |
165 0); | |
166 if (!buffer_object) { | |
167 LOG(ERROR) << "drm_intel_bo_alloc_tiled failed."; | |
168 return NULL; | |
169 } | |
170 | |
171 // |pitch| must match what we expect. | |
172 if (static_cast<uint64>(pitch) != expected_pitch) { | |
173 LOG(ERROR) << "Unexpected pitch: " << pitch << " vs " << expected_pitch; | |
174 drm_intel_bo_unreference(buffer_object); | |
175 return NULL; | |
176 } | |
177 | |
178 return buffer_object; | |
179 } | |
180 | |
181 drm_intel_bo* CreateBufferObjectFromPrimeFd(gfx::Size size, | |
182 unsigned internalformat, | |
183 int prime_fd) { | |
184 DCHECK(thread_checker_.CalledOnValidThread()); | |
185 | |
186 if (!buffer_manager_) | |
187 return NULL; | |
188 | |
189 uint64 pitch = BufferObjectPitch(size, internalformat); | |
190 if (!base::IsValueInRangeForNumericType<uint32>(pitch)) | |
191 return NULL; | |
192 | |
193 uint64 buffer_size = pitch * size.height(); | |
194 if (!base::IsValueInRangeForNumericType<int>(buffer_size)) | |
195 return NULL; | |
196 | |
197 return drm_intel_bo_gem_create_from_prime( | |
198 buffer_manager_, prime_fd, buffer_size); | |
199 } | |
200 | |
201 private: | |
202 base::ThreadChecker thread_checker_; | |
203 base::ScopedFD dri_fd_; | |
204 drm_intel_bufmgr* buffer_manager_; | |
205 }; | |
206 base::LazyInstance<BufferObjectFactory>::Leaky g_buffer_object_factory = | |
207 LAZY_INSTANCE_INITIALIZER; | |
208 | |
209 } // namespace | |
210 | |
211 GpuMemoryBufferImplIntelDRM::GpuMemoryBufferImplIntelDRM( | |
212 gfx::Size size, | |
213 unsigned internalformat) | |
214 : GpuMemoryBufferImpl(size, internalformat), buffer_object_(NULL) {} | |
215 | |
216 GpuMemoryBufferImplIntelDRM::~GpuMemoryBufferImplIntelDRM() { | |
217 if (buffer_object_) | |
218 drm_intel_bo_unreference(buffer_object_); | |
219 } | |
220 | |
221 // static | |
222 bool GpuMemoryBufferImplIntelDRM::IsFormatSupported(unsigned internalformat) { | |
223 switch (internalformat) { | |
224 case GL_BGRA8_EXT: | |
225 return true; | |
226 default: | |
227 return false; | |
228 } | |
229 } | |
230 | |
231 // static | |
232 drm_intel_bo* GpuMemoryBufferImplIntelDRM::CreateBufferObject( | |
233 gfx::Size size, | |
234 unsigned internalformat) { | |
235 return g_buffer_object_factory.Pointer()->CreateBufferObject(size, | |
236 internalformat); | |
237 } | |
238 | |
239 // static | |
240 bool GpuMemoryBufferImplIntelDRM::AllocateBufferObject( | |
241 gfx::Size size, | |
242 unsigned internalformat, | |
243 base::SharedMemoryHandle* handle) { | |
244 drm_intel_bo* buffer_object = CreateBufferObject(size, internalformat); | |
245 if (!buffer_object) | |
246 return false; | |
247 | |
248 ExportBufferObject(buffer_object, handle); | |
249 drm_intel_bo_unreference(buffer_object); | |
250 return true; | |
251 } | |
252 | |
253 bool GpuMemoryBufferImplIntelDRM::Initialize( | |
254 gfx::GpuMemoryBufferHandle handle) { | |
255 TRACE_EVENT0("gpu", "GpuMemoryBufferImplIntelDRM::Initialize"); | |
256 | |
257 DCHECK(!buffer_object_); | |
258 buffer_object_ = | |
259 g_buffer_object_factory.Pointer()->CreateBufferObjectFromPrimeFd( | |
260 size_, internalformat_, handle.handle.fd); | |
261 return !!buffer_object_; | |
262 } | |
263 | |
264 bool GpuMemoryBufferImplIntelDRM::InitializeFromBufferObject( | |
265 drm_intel_bo* buffer_object) { | |
266 DCHECK(!buffer_object_); | |
267 buffer_object_ = buffer_object; | |
268 return true; | |
269 } | |
270 | |
271 void* GpuMemoryBufferImplIntelDRM::Map(AccessMode mode) { | |
272 TRACE_EVENT0("gpu", "GpuMemoryBufferImplIntelDRM::Map"); | |
273 | |
274 DCHECK(!mapped_); | |
275 DCHECK(buffer_object_); | |
276 drm_intel_bo_map(buffer_object_, WriteEnable(mode)); | |
277 mapped_ = true; | |
278 return buffer_object_->virt; | |
279 } | |
280 | |
281 void GpuMemoryBufferImplIntelDRM::Unmap() { | |
282 TRACE_EVENT0("gpu", "GpuMemoryBufferImplIntelDRM::Unmap"); | |
283 | |
284 DCHECK(mapped_); | |
285 drm_intel_bo_unmap(buffer_object_); | |
286 mapped_ = false; | |
287 } | |
288 | |
289 gfx::GpuMemoryBufferHandle GpuMemoryBufferImplIntelDRM::GetHandle() const { | |
290 gfx::GpuMemoryBufferHandle handle; | |
291 handle.type = gfx::INTEL_DRM_BUFFER; | |
292 DCHECK(buffer_object_); | |
293 ExportBufferObject(buffer_object_, &handle.handle); | |
fjhenigman
2014/04/11 02:45:28
GetHandle() should cache the result of drm_intel_b
reveman
2014/04/11 05:54:27
Done.
| |
294 return handle; | |
295 } | |
296 | |
297 } // namespace content | |
OLD | NEW |