OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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/browser/renderer_host/image_transport_client.h" | |
6 | |
7 #include <X11/Xlib.h> | |
8 #include <X11/extensions/Xcomposite.h> | |
9 | |
10 #include "base/debug/trace_event.h" | |
11 #include "base/lazy_instance.h" | |
12 #include "base/memory/scoped_ptr.h" | |
13 #include "base/message_loop.h" | |
14 #include "content/browser/renderer_host/image_transport_factory.h" | |
15 #include "third_party/angle/include/EGL/egl.h" | |
16 #include "third_party/angle/include/EGL/eglext.h" | |
17 #include "ui/gfx/size.h" | |
18 #include "ui/gl/gl_bindings.h" | |
19 #include "ui/gl/gl_implementation.h" | |
20 #include "ui/gl/gl_surface_egl.h" | |
21 #include "ui/gl/gl_surface_glx.h" | |
22 #include "ui/gl/scoped_make_current.h" | |
23 | |
24 namespace { | |
25 | |
26 class ScopedPtrXFree { | |
27 public: | |
28 void operator()(void* x) const { | |
29 ::XFree(x); | |
30 } | |
31 }; | |
32 | |
33 GLuint CreateTexture() { | |
34 GLuint texture; | |
35 glGenTextures(1, &texture); | |
36 glBindTexture(GL_TEXTURE_2D, texture); | |
37 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
38 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
39 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
40 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
41 return texture; | |
42 } | |
43 | |
44 class ImageTransportClientEGL : public ImageTransportClient { | |
45 public: | |
46 ImageTransportClientEGL(ImageTransportFactory* factory, const gfx::Size& size) | |
47 : ImageTransportClient(true, size), | |
48 factory_(factory), | |
49 image_(NULL) { | |
50 } | |
51 | |
52 virtual bool Initialize(uint64* surface_handle) OVERRIDE { | |
53 scoped_ptr<gfx::ScopedMakeCurrent> bind(factory_->GetScopedMakeCurrent()); | |
54 image_ = eglCreateImageKHR( | |
55 gfx::GLSurfaceEGL::GetHardwareDisplay(), EGL_NO_CONTEXT, | |
56 EGL_NATIVE_PIXMAP_KHR, reinterpret_cast<void*>(*surface_handle), NULL); | |
57 if (!image_) | |
58 return false; | |
59 set_texture_id(CreateTexture()); | |
60 glBindTexture(GL_TEXTURE_2D, texture_id()); | |
61 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image_); | |
62 glFlush(); | |
63 return true; | |
64 } | |
65 | |
66 virtual void Update() OVERRIDE {} | |
67 virtual TransportDIB::Handle Handle() const OVERRIDE { | |
68 return TransportDIB::DefaultHandleValue(); | |
69 } | |
70 | |
71 protected: | |
72 virtual ~ImageTransportClientEGL() { | |
73 scoped_ptr<gfx::ScopedMakeCurrent> bind(factory_->GetScopedMakeCurrent()); | |
74 if (image_) | |
75 eglDestroyImageKHR(gfx::GLSurfaceEGL::GetHardwareDisplay(), image_); | |
76 unsigned int texture = texture_id(); | |
77 if (texture) | |
78 glDeleteTextures(1, &texture); | |
79 glFlush(); | |
80 } | |
81 | |
82 private: | |
83 ImageTransportFactory* factory_; | |
84 EGLImageKHR image_; | |
85 }; | |
86 | |
87 class ImageTransportClientGLX : public ImageTransportClient { | |
88 public: | |
89 ImageTransportClientGLX(ImageTransportFactory* factory, const gfx::Size& size) | |
90 : ImageTransportClient(false, size), | |
91 factory_(factory), | |
92 pixmap_(0), | |
93 glx_pixmap_(0), | |
94 acquired_(false) { | |
95 } | |
96 | |
97 virtual bool Initialize(uint64* surface_handle) OVERRIDE { | |
98 TRACE_EVENT0("renderer_host", "ImageTransportClientGLX::Initialize"); | |
99 Display* dpy = base::MessagePumpForUI::GetDefaultXDisplay(); | |
100 | |
101 scoped_ptr<gfx::ScopedMakeCurrent> bind(factory_->GetScopedMakeCurrent()); | |
102 if (!InitializeOneOff(dpy)) | |
103 return false; | |
104 | |
105 // Create pixmap from window. | |
106 // We receive a window here rather than a pixmap directly because drivers | |
107 // require (or required) that the pixmap used to create the GL texture be | |
108 // created in the same process as the texture. | |
109 pixmap_ = XCompositeNameWindowPixmap(dpy, *surface_handle); | |
110 | |
111 const int pixmapAttribs[] = { | |
112 GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, | |
113 GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT, | |
114 0 | |
115 }; | |
116 | |
117 glx_pixmap_ = glXCreatePixmap(dpy, fbconfig_.Get(), pixmap_, pixmapAttribs); | |
118 | |
119 set_texture_id(CreateTexture()); | |
120 glFlush(); | |
121 return true; | |
122 } | |
123 | |
124 virtual void Update() OVERRIDE { | |
125 TRACE_EVENT0("renderer_host", "ImageTransportClientGLX::Update"); | |
126 Display* dpy = base::MessagePumpForUI::GetDefaultXDisplay(); | |
127 scoped_ptr<gfx::ScopedMakeCurrent> bind(factory_->GetScopedMakeCurrent()); | |
128 glBindTexture(GL_TEXTURE_2D, texture_id()); | |
129 if (acquired_) | |
130 glXReleaseTexImageEXT(dpy, glx_pixmap_, GLX_FRONT_LEFT_EXT); | |
131 glXBindTexImageEXT(dpy, glx_pixmap_, GLX_FRONT_LEFT_EXT, NULL); | |
132 acquired_ = true; | |
133 glFlush(); | |
134 } | |
135 | |
136 virtual TransportDIB::Handle Handle() const OVERRIDE { | |
137 return TransportDIB::DefaultHandleValue(); | |
138 } | |
139 | |
140 protected: | |
141 virtual ~ImageTransportClientGLX() { | |
142 scoped_ptr<gfx::ScopedMakeCurrent> bind(factory_->GetScopedMakeCurrent()); | |
143 Display* dpy = base::MessagePumpForUI::GetDefaultXDisplay(); | |
144 if (glx_pixmap_) { | |
145 if (acquired_) | |
146 glXReleaseTexImageEXT(dpy, glx_pixmap_, GLX_FRONT_LEFT_EXT); | |
147 glXDestroyGLXPixmap(dpy, glx_pixmap_); | |
148 } | |
149 if (pixmap_) | |
150 XFreePixmap(dpy, pixmap_); | |
151 unsigned int texture = texture_id(); | |
152 if (texture) | |
153 glDeleteTextures(1, &texture); | |
154 glFlush(); | |
155 } | |
156 | |
157 private: | |
158 static bool InitializeOneOff(Display* dpy) { | |
159 static bool initialized = false; | |
160 if (initialized) | |
161 return true; | |
162 | |
163 int event_base, error_base; | |
164 if (XCompositeQueryExtension(dpy, &event_base, &error_base)) { | |
165 int major = 0, minor = 2; | |
166 XCompositeQueryVersion(dpy, &major, &minor); | |
167 if (major == 0 && minor < 2) { | |
168 LOG(ERROR) << "Pixmap from window not supported."; | |
169 return false; | |
170 } | |
171 } | |
172 // Wrap the pixmap in a GLXPixmap | |
173 int screen = DefaultScreen(dpy); | |
174 XWindowAttributes gwa; | |
175 XGetWindowAttributes(dpy, RootWindow(dpy, screen), &gwa); | |
176 unsigned int visualid = XVisualIDFromVisual(gwa.visual); | |
177 | |
178 int nfbconfigs, config; | |
179 scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> fbconfigs( | |
180 glXGetFBConfigs(dpy, screen, &nfbconfigs)); | |
181 | |
182 for (config = 0; config < nfbconfigs; config++) { | |
183 XVisualInfo* visinfo = glXGetVisualFromFBConfig( | |
184 dpy, fbconfigs.get()[config]); | |
185 if (!visinfo || visinfo->visualid != visualid) | |
186 continue; | |
187 | |
188 int value; | |
189 glXGetFBConfigAttrib(dpy, | |
190 fbconfigs.get()[config], | |
191 GLX_DRAWABLE_TYPE, | |
192 &value); | |
193 if (!(value & GLX_PIXMAP_BIT)) | |
194 continue; | |
195 | |
196 glXGetFBConfigAttrib(dpy, | |
197 fbconfigs.get()[config], | |
198 GLX_BIND_TO_TEXTURE_TARGETS_EXT, | |
199 &value); | |
200 if (!(value & GLX_TEXTURE_2D_BIT_EXT)) | |
201 continue; | |
202 | |
203 glXGetFBConfigAttrib(dpy, | |
204 fbconfigs.get()[config], | |
205 GLX_BIND_TO_TEXTURE_RGB_EXT, | |
206 &value); | |
207 if (value == GL_FALSE) | |
208 continue; | |
209 | |
210 break; | |
211 } | |
212 | |
213 if (config == nfbconfigs) { | |
214 LOG(ERROR) | |
215 << "Could not find configuration suitable for binding a pixmap " | |
216 << "as a texture."; | |
217 return false; | |
218 } | |
219 fbconfig_.Get() = fbconfigs.get()[config]; | |
220 initialized = true; | |
221 return initialized; | |
222 } | |
223 | |
224 ImageTransportFactory* factory_; | |
225 XID pixmap_; | |
226 XID glx_pixmap_; | |
227 bool acquired_; | |
228 static base::LazyInstance<GLXFBConfig> fbconfig_; | |
229 }; | |
230 | |
231 base::LazyInstance<GLXFBConfig> ImageTransportClientGLX::fbconfig_ = | |
232 LAZY_INSTANCE_INITIALIZER; | |
233 | |
234 class ImageTransportClientOSMesa : public ImageTransportClient { | |
235 public: | |
236 ImageTransportClientOSMesa(ImageTransportFactory* factory, | |
237 const gfx::Size& size) | |
238 : ImageTransportClient(false, size), | |
239 factory_(factory) { | |
240 } | |
241 | |
242 virtual bool Initialize(uint64* surface_handle) OVERRIDE { | |
243 // We expect to make the handle here, so don't want the other end giving us | |
244 // one. | |
245 DCHECK_EQ(*surface_handle, static_cast<uint64>(0)); | |
246 | |
247 // It's possible that this ID gneration could clash with IDs from other | |
248 // AcceleratedSurfaceContainerTouch* objects, however we should never have | |
249 // ids active from more than one type at the same time, so we have free | |
250 // reign of the id namespace. | |
251 *surface_handle = next_handle_++; | |
252 | |
253 shared_mem_.reset( | |
254 TransportDIB::Create(size().GetArea() * 4, // GL_RGBA=4 B/px | |
255 *surface_handle)); | |
256 if (!shared_mem_.get()) | |
257 return false; | |
258 | |
259 scoped_ptr<gfx::ScopedMakeCurrent> bind(factory_->GetScopedMakeCurrent()); | |
260 set_texture_id(CreateTexture()); | |
261 glFlush(); | |
262 return true; | |
263 } | |
264 | |
265 virtual void Update() OVERRIDE { | |
266 glBindTexture(GL_TEXTURE_2D, texture_id()); | |
267 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, | |
268 size().width(), size().height(), 0, | |
269 GL_RGBA, GL_UNSIGNED_BYTE, shared_mem_->memory()); | |
270 glFlush(); | |
271 } | |
272 | |
273 virtual TransportDIB::Handle Handle() const OVERRIDE { | |
274 return shared_mem_->handle(); | |
275 } | |
276 | |
277 protected: | |
278 virtual ~ImageTransportClientOSMesa() { | |
279 unsigned int texture = texture_id(); | |
280 if (texture) { | |
281 scoped_ptr<gfx::ScopedMakeCurrent> bind( | |
282 factory_->GetScopedMakeCurrent()); | |
283 glDeleteTextures(1, &texture); | |
284 glFlush(); | |
285 } | |
286 } | |
287 | |
288 private: | |
289 ImageTransportFactory* factory_; | |
290 scoped_ptr<TransportDIB> shared_mem_; | |
291 static uint32 next_handle_; | |
292 }; | |
293 uint32 ImageTransportClientOSMesa::next_handle_ = 0; | |
294 | |
295 } // anonymous namespace | |
296 | |
297 ImageTransportClient* ImageTransportClient::Create( | |
298 ImageTransportFactory* factory, | |
299 const gfx::Size& size) { | |
300 switch (gfx::GetGLImplementation()) { | |
301 case gfx::kGLImplementationOSMesaGL: | |
302 return new ImageTransportClientOSMesa(factory, size); | |
303 case gfx::kGLImplementationDesktopGL: | |
304 return new ImageTransportClientGLX(factory, size); | |
305 case gfx::kGLImplementationEGLGLES2: | |
306 return new ImageTransportClientEGL(factory, size); | |
307 default: | |
308 NOTREACHED(); | |
309 return NULL; | |
310 } | |
311 } | |
OLD | NEW |