OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 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 #if defined(ENABLE_GPU) | |
6 | |
7 #include "content/common/gpu/image_transport_surface_linux.h" | |
8 | |
9 // This conflicts with the defines in Xlib.h and must come first. | |
10 #include "content/common/gpu/gpu_messages.h" | |
11 | |
12 #include <map> | |
13 #include <X11/Xlib.h> | |
14 #include <X11/extensions/Xcomposite.h> | |
15 | |
16 #include "base/callback.h" | |
17 #include "content/common/gpu/gpu_channel.h" | |
18 #include "content/common/gpu/gpu_channel_manager.h" | |
19 #include "content/common/gpu/gpu_command_buffer_stub.h" | |
20 #include "gpu/command_buffer/service/gpu_scheduler.h" | |
21 #include "third_party/angle/include/EGL/egl.h" | |
22 #include "third_party/angle/include/EGL/eglext.h" | |
23 #include "ui/gfx/gl/gl_bindings.h" | |
24 #include "ui/gfx/gl/gl_implementation.h" | |
25 #include "ui/gfx/gl/gl_surface_egl.h" | |
26 #include "ui/gfx/gl/gl_surface_glx.h" | |
27 #include "ui/gfx/surface/accelerated_surface_linux.h" | |
28 | |
29 namespace { | |
30 | |
31 // We are backed by an Pbuffer offscreen surface for the purposes of creating a | |
32 // context, but use FBOs to render to X Pixmap backed EGLImages. | |
33 class EGLImageTransportSurface : public ImageTransportSurface, | |
34 public gfx::PbufferGLSurfaceEGL { | |
35 public: | |
36 explicit EGLImageTransportSurface(GpuCommandBufferStub* stub); | |
37 | |
38 // GLSurface implementation | |
39 virtual bool Initialize(); | |
40 virtual void Destroy(); | |
41 virtual bool IsOffscreen(); | |
42 virtual bool SwapBuffers(); | |
43 virtual gfx::Size GetSize(); | |
44 virtual void OnMakeCurrent(); | |
45 virtual unsigned int GetBackingFrameBufferObject(); | |
46 | |
47 protected: | |
48 // ImageTransportSurface implementation | |
49 virtual void OnSetSurfaceACK(uint64 surface_id); | |
50 virtual void OnBuffersSwappedACK(); | |
51 virtual void Resize(gfx::Size size); | |
52 | |
53 private: | |
54 virtual ~EGLImageTransportSurface(); | |
55 void ReleaseSurface(scoped_refptr<AcceleratedSurface>& surface); | |
56 | |
57 uint32 fbo_id_; | |
58 uint32 depth_id_; | |
59 gfx::Size depth_buffer_size_; | |
60 | |
61 scoped_refptr<AcceleratedSurface> back_surface_; | |
62 scoped_refptr<AcceleratedSurface> front_surface_; | |
63 | |
64 DISALLOW_COPY_AND_ASSIGN(EGLImageTransportSurface); | |
65 }; | |
66 | |
67 // We are backed by an Pbuffer offscreen surface for the purposes of creating a | |
68 // context, but use FBOs to render to X Pixmap backed EGLImages. | |
69 class GLXImageTransportSurface : public ImageTransportSurface, | |
70 public gfx::NativeViewGLSurfaceGLX { | |
71 public: | |
72 explicit GLXImageTransportSurface(GpuCommandBufferStub* stub); | |
73 | |
74 // gfx::GLSurface implementation: | |
75 virtual bool Initialize(); | |
76 virtual void Destroy(); | |
77 virtual bool SwapBuffers(); | |
78 virtual gfx::Size GetSize(); | |
79 | |
80 protected: | |
81 // ImageTransportSurface implementation: | |
82 void OnSetSurfaceACK(uint64 surface_id); | |
83 void OnBuffersSwappedACK(); | |
84 void Resize(gfx::Size size); | |
85 | |
86 private: | |
87 virtual ~GLXImageTransportSurface(); | |
88 | |
89 // Tell the browser to release the surface. | |
90 void ReleaseSurface(); | |
91 | |
92 XID dummy_parent_; | |
93 gfx::Size size_; | |
94 | |
95 // Whether or not the image has been bound on the browser side. | |
96 bool bound_; | |
97 | |
98 DISALLOW_COPY_AND_ASSIGN(GLXImageTransportSurface); | |
99 }; | |
100 | |
101 EGLImageTransportSurface::EGLImageTransportSurface(GpuCommandBufferStub* stub) : | |
102 ImageTransportSurface(stub), | |
103 gfx::PbufferGLSurfaceEGL(gfx::Size(1,1)), | |
104 fbo_id_(0) { | |
105 } | |
106 | |
107 EGLImageTransportSurface::~EGLImageTransportSurface() { | |
108 } | |
109 | |
110 bool EGLImageTransportSurface::Initialize() { | |
111 if (!ImageTransportSurface::Initialize()) | |
112 return false; | |
113 return PbufferGLSurfaceEGL::Initialize(); | |
114 } | |
115 | |
116 void EGLImageTransportSurface::Destroy() { | |
117 if (depth_id_) { | |
118 glDeleteRenderbuffersEXT(1, &depth_id_); | |
119 depth_id_ = 0; | |
120 } | |
121 | |
122 if (back_surface_.get()) | |
123 ReleaseSurface(back_surface_); | |
124 if (front_surface_.get()) | |
125 ReleaseSurface(front_surface_); | |
126 | |
127 ImageTransportSurface::Destroy(); | |
128 PbufferGLSurfaceEGL::Destroy(); | |
129 } | |
130 | |
131 bool EGLImageTransportSurface::IsOffscreen() { | |
132 return false; | |
133 } | |
134 | |
135 void EGLImageTransportSurface::OnMakeCurrent() { | |
136 if (fbo_id_) | |
137 return; | |
138 | |
139 glGenFramebuffersEXT(1, &fbo_id_); | |
140 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo_id_); | |
141 Resize(gfx::Size(1,1)); | |
142 | |
143 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); | |
144 if (status != GL_FRAMEBUFFER_COMPLETE) { | |
145 LOG(ERROR) << "Framebuffer incomplete."; | |
146 } | |
147 } | |
148 | |
149 unsigned int EGLImageTransportSurface::GetBackingFrameBufferObject() { | |
150 return fbo_id_; | |
151 } | |
152 | |
153 void EGLImageTransportSurface::ReleaseSurface( | |
154 scoped_refptr<AcceleratedSurface>& surface) { | |
155 if (surface.get()) { | |
156 GpuHostMsg_AcceleratedSurfaceRelease_Params params; | |
157 params.renderer_id = stub()->renderer_id(); | |
158 params.render_view_id = stub()->render_view_id(); | |
159 params.identifier = back_surface_->pixmap(); | |
160 params.route_id = route_id(); | |
161 Send(new GpuHostMsg_AcceleratedSurfaceRelease(params)); | |
162 surface = NULL; | |
163 } | |
164 } | |
165 | |
166 void EGLImageTransportSurface::Resize(gfx::Size size) { | |
167 if (back_surface_.get()) | |
168 ReleaseSurface(back_surface_); | |
169 | |
170 if (depth_id_ && depth_buffer_size_ != size) { | |
171 glDeleteRenderbuffersEXT(1, &depth_id_); | |
172 depth_id_ = 0; | |
173 } | |
174 | |
175 if (!depth_id_) { | |
176 glGenRenderbuffersEXT(1, &depth_id_); | |
177 glBindRenderbufferEXT(GL_RENDERBUFFER, depth_id_); | |
178 glRenderbufferStorageEXT(GL_RENDERBUFFER, | |
179 GL_DEPTH24_STENCIL8, | |
180 size.width(), | |
181 size.height()); | |
182 glBindRenderbufferEXT(GL_RENDERBUFFER, 0); | |
183 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, | |
184 GL_DEPTH_ATTACHMENT, | |
185 GL_RENDERBUFFER, | |
186 depth_id_); | |
187 depth_buffer_size_ = size; | |
188 } | |
189 | |
190 back_surface_ = new AcceleratedSurface(size); | |
191 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, | |
192 GL_COLOR_ATTACHMENT0, | |
193 GL_TEXTURE_2D, | |
194 back_surface_->texture(), | |
195 0); | |
196 glFlush(); | |
197 | |
198 GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params params; | |
199 params.renderer_id = stub()->renderer_id(); | |
200 params.render_view_id = stub()->render_view_id(); | |
201 params.width = size.width(); | |
202 params.height = size.height(); | |
203 params.identifier = back_surface_->pixmap(); | |
204 params.route_id = route_id(); | |
205 Send(new GpuHostMsg_AcceleratedSurfaceSetIOSurface(params)); | |
206 | |
207 scheduler()->SetScheduled(false); | |
208 } | |
209 | |
210 bool EGLImageTransportSurface::SwapBuffers() { | |
211 front_surface_.swap(back_surface_); | |
212 DCHECK_NE(front_surface_.get(), static_cast<AcceleratedSurface*>(NULL)); | |
213 glFlush(); | |
214 | |
215 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; | |
216 params.renderer_id = stub()->renderer_id(); | |
217 params.render_view_id = stub()->render_view_id(); | |
218 params.surface_id = front_surface_->pixmap(); | |
219 params.route_id = route_id(); | |
220 Send(new GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params)); | |
221 | |
222 gfx::Size expected_size = front_surface_->size(); | |
223 if (!back_surface_.get() || back_surface_->size() != expected_size) { | |
224 Resize(expected_size); | |
225 } else { | |
226 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, | |
227 GL_COLOR_ATTACHMENT0, | |
228 GL_TEXTURE_2D, | |
229 back_surface_->texture(), | |
230 0); | |
231 } | |
232 scheduler()->SetScheduled(false); | |
233 return true; | |
234 } | |
235 | |
236 gfx::Size EGLImageTransportSurface::GetSize() { | |
237 return back_surface_->size(); | |
238 } | |
239 | |
240 void EGLImageTransportSurface::OnSetSurfaceACK( | |
241 uint64 surface_id) { | |
242 DCHECK_EQ(back_surface_->pixmap(), surface_id); | |
243 scheduler()->SetScheduled(true); | |
244 } | |
245 | |
246 void EGLImageTransportSurface::OnBuffersSwappedACK() { | |
247 scheduler()->SetScheduled(true); | |
248 } | |
249 | |
250 GLXImageTransportSurface::GLXImageTransportSurface(GpuCommandBufferStub* stub) : | |
251 ImageTransportSurface(stub), | |
252 gfx::NativeViewGLSurfaceGLX(), | |
253 dummy_parent_(0), | |
254 size_(1, 1), | |
255 bound_(false) { | |
256 } | |
257 | |
258 GLXImageTransportSurface::~GLXImageTransportSurface() { | |
259 } | |
260 | |
261 bool GLXImageTransportSurface::Initialize() { | |
262 // Create a dummy window to host the real window. | |
263 Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); | |
264 XSetWindowAttributes swa; | |
265 swa.event_mask = StructureNotifyMask; | |
266 swa.override_redirect = True; | |
267 dummy_parent_ = XCreateWindow( | |
268 dpy, | |
269 RootWindow(dpy, DefaultScreen(dpy)), // parent | |
270 -100, -100, 1, 1, | |
271 0, // border width | |
272 CopyFromParent, // depth | |
273 InputOutput, | |
274 CopyFromParent, // visual | |
275 CWEventMask | CWOverrideRedirect, &swa); | |
276 XMapWindow(dpy, dummy_parent_); | |
277 | |
278 swa.event_mask = StructureNotifyMask; | |
279 swa.override_redirect = false; | |
280 window_ = XCreateWindow(dpy, | |
281 dummy_parent_, | |
282 0, 0, size_.width(), size_.height(), | |
283 0, // border width | |
284 CopyFromParent, // depth | |
285 InputOutput, | |
286 CopyFromParent, // visual | |
287 CWEventMask, &swa); | |
288 XMapWindow(dpy, window_); | |
289 while(1) { | |
290 XEvent event; | |
291 XNextEvent(dpy, &event); | |
292 if (event.type == MapNotify && event.xmap.window == window_) | |
293 break; | |
294 } | |
295 // Manual setting must be used to avoid unnecessary rendering by server. | |
296 XCompositeRedirectWindow(dpy, window_, CompositeRedirectManual); | |
297 Resize(size_); | |
298 | |
299 if (!ImageTransportSurface::Initialize()) | |
300 return false; | |
301 return gfx::NativeViewGLSurfaceGLX::Initialize(); | |
302 } | |
303 | |
304 void GLXImageTransportSurface::Destroy() { | |
305 if (bound_) | |
306 ReleaseSurface(); | |
307 | |
308 if (window_) { | |
309 Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); | |
310 XDestroyWindow(dpy, window_); | |
311 XDestroyWindow(dpy, dummy_parent_); | |
312 } | |
313 | |
314 ImageTransportSurface::Destroy(); | |
315 gfx::NativeViewGLSurfaceGLX::Destroy(); | |
316 } | |
317 | |
318 void GLXImageTransportSurface::ReleaseSurface() { | |
319 DCHECK(bound_); | |
320 GpuHostMsg_AcceleratedSurfaceRelease_Params params; | |
321 params.renderer_id = stub()->renderer_id(); | |
322 params.render_view_id = stub()->render_view_id(); | |
323 params.identifier = window_; | |
324 params.route_id = route_id(); | |
325 Send(new GpuHostMsg_AcceleratedSurfaceRelease(params)); | |
326 } | |
327 | |
328 void GLXImageTransportSurface::Resize(gfx::Size size) { | |
329 size_ = size; | |
330 if (bound_) { | |
331 ReleaseSurface(); | |
332 bound_ = false; | |
333 } | |
334 | |
335 Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); | |
336 XResizeWindow(dpy, window_, size_.width(), size_.height()); | |
337 XFlush(dpy); | |
338 | |
339 GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params params; | |
340 params.renderer_id = stub()->renderer_id(); | |
341 params.render_view_id = stub()->render_view_id(); | |
342 params.width = size_.width(); | |
343 params.height = size_.height(); | |
344 params.identifier = window_; | |
345 params.route_id = route_id(); | |
346 Send(new GpuHostMsg_AcceleratedSurfaceSetIOSurface(params)); | |
347 | |
348 scheduler()->SetScheduled(false); | |
349 } | |
350 | |
351 bool GLXImageTransportSurface::SwapBuffers() { | |
352 gfx::NativeViewGLSurfaceGLX::SwapBuffers(); | |
apatrick_chromium
2011/07/21 21:03:02
Out of interest, why does it not need to unschedul
jonathan.backer
2011/07/22 13:12:40
My first implementation had it. Then I dropped it.
| |
353 glFlush(); | |
354 | |
355 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; | |
356 params.renderer_id = stub()->renderer_id(); | |
357 params.render_view_id = stub()->render_view_id(); | |
358 params.surface_id = window_; | |
359 params.route_id = route_id(); | |
360 Send(new GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params)); | |
361 | |
362 return true; | |
363 } | |
364 | |
365 gfx::Size GLXImageTransportSurface::GetSize() { | |
366 return size_; | |
367 } | |
368 | |
369 void GLXImageTransportSurface::OnSetSurfaceACK( | |
370 uint64 surface_id) { | |
371 DCHECK(!bound_); | |
372 bound_ = true; | |
373 scheduler()->SetScheduled(true); | |
374 } | |
375 | |
376 void GLXImageTransportSurface::OnBuffersSwappedACK() { | |
377 } | |
378 | |
379 } // namespace | |
380 | |
381 ImageTransportSurface::ImageTransportSurface(GpuCommandBufferStub* stub) : | |
382 stub_(stub) { | |
383 GpuChannelManager* gpu_channel_manager | |
384 = stub_->channel()->gpu_channel_manager(); | |
385 route_id_ = gpu_channel_manager->GenerateRouteID(); | |
386 gpu_channel_manager->AddRoute(route_id_, this); | |
387 } | |
388 | |
389 ImageTransportSurface::~ImageTransportSurface() { | |
390 GpuChannelManager* gpu_channel_manager | |
391 = stub_->channel()->gpu_channel_manager(); | |
392 gpu_channel_manager->RemoveRoute(route_id_); | |
393 } | |
394 | |
395 bool ImageTransportSurface::Initialize() { | |
396 stub_->scheduler()->SetResizeCallback( | |
397 NewCallback(this, &ImageTransportSurface::Resize)); | |
398 return true; | |
399 } | |
400 | |
401 void ImageTransportSurface::Destroy() { | |
402 stub_->scheduler()->SetResizeCallback(NULL); | |
403 } | |
404 | |
405 bool ImageTransportSurface::OnMessageReceived(const IPC::Message& message) { | |
406 bool handled = true; | |
407 IPC_BEGIN_MESSAGE_MAP(ImageTransportSurface, message) | |
408 IPC_MESSAGE_HANDLER(AcceleratedSurfaceMsg_SetSurfaceACK, | |
409 OnSetSurfaceACK) | |
410 IPC_MESSAGE_HANDLER(AcceleratedSurfaceMsg_BuffersSwappedACK, | |
411 OnBuffersSwappedACK) | |
412 IPC_MESSAGE_UNHANDLED(handled = false) | |
413 IPC_END_MESSAGE_MAP() | |
414 return handled; | |
415 } | |
416 | |
417 bool ImageTransportSurface::Send(IPC::Message* message) { | |
418 GpuChannelManager* gpu_channel_manager = | |
419 stub_->channel()->gpu_channel_manager(); | |
420 return gpu_channel_manager->Send(message); | |
421 } | |
422 | |
423 gpu::GpuScheduler* ImageTransportSurface::scheduler() { | |
424 return stub_->scheduler(); | |
425 } | |
426 | |
427 // static | |
428 scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateSurface( | |
429 GpuCommandBufferStub* stub) { | |
430 scoped_refptr<gfx::GLSurface> surface; | |
431 switch (gfx::GetGLImplementation()) { | |
432 case gfx::kGLImplementationDesktopGL: | |
433 surface = new GLXImageTransportSurface(stub); | |
434 break; | |
435 case gfx::kGLImplementationEGLGLES2: | |
436 surface = new EGLImageTransportSurface(stub); | |
437 break; | |
438 default: | |
439 NOTREACHED(); | |
440 return NULL; | |
441 } | |
442 if (surface->Initialize()) | |
443 return surface; | |
444 else | |
445 return NULL; | |
446 } | |
447 | |
448 #endif // defined(USE_GPU) | |
OLD | NEW |