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 #include "content/browser/renderer_host/accelerated_surface_container_linux.h" | |
6 | |
7 #include <X11/Xlib.h> | |
8 #include <X11/extensions/Xcomposite.h> | |
9 | |
10 #include "base/lazy_instance.h" | |
11 #include "base/memory/scoped_ptr.h" | |
12 #include "third_party/angle/include/EGL/egl.h" | |
13 #include "third_party/angle/include/EGL/eglext.h" | |
14 #include "ui/gfx/gl/gl_bindings.h" | |
15 #include "ui/gfx/gl/gl_implementation.h" | |
16 #include "ui/gfx/gl/gl_surface_egl.h" | |
17 #include "ui/gfx/gl/gl_surface_glx.h" | |
18 #include "ui/gfx/rect.h" | |
19 #include "ui/gfx/transform.h" | |
20 | |
21 namespace { | |
22 | |
23 class AcceleratedSurfaceContainerLinuxEGL | |
24 : public AcceleratedSurfaceContainerLinux { | |
25 public: | |
26 explicit AcceleratedSurfaceContainerLinuxEGL(const gfx::Size& size); | |
27 | |
28 virtual bool Initialize(uint64* surface_id) OVERRIDE; | |
29 | |
30 // TextureGL implementation | |
31 virtual void Draw(const ui::TextureDrawParams& params, | |
32 const gfx::Rect& clip_bounds_in_texture) OVERRIDE; | |
33 | |
34 private: | |
35 virtual ~AcceleratedSurfaceContainerLinuxEGL(); | |
36 | |
37 void* image_; | |
38 | |
39 DISALLOW_COPY_AND_ASSIGN(AcceleratedSurfaceContainerLinuxEGL); | |
40 }; | |
41 | |
42 class AcceleratedSurfaceContainerLinuxGLX | |
43 : public AcceleratedSurfaceContainerLinux { | |
44 public: | |
45 explicit AcceleratedSurfaceContainerLinuxGLX(const gfx::Size& size); | |
46 | |
47 virtual bool Initialize(uint64* surface_id) OVERRIDE; | |
48 | |
49 // TextureGL implementation | |
50 virtual void Draw(const ui::TextureDrawParams& params, | |
51 const gfx::Rect& clip_bounds_in_texture) OVERRIDE; | |
52 | |
53 protected: | |
54 static bool InitializeOneOff(); | |
55 | |
56 static base::LazyInstance<GLXFBConfig> fbconfig_; | |
57 | |
58 private: | |
59 virtual ~AcceleratedSurfaceContainerLinuxGLX(); | |
60 | |
61 XID pixmap_; | |
62 XID glx_pixmap_; | |
63 | |
64 DISALLOW_COPY_AND_ASSIGN(AcceleratedSurfaceContainerLinuxGLX); | |
65 }; | |
66 | |
67 class AcceleratedSurfaceContainerLinuxOSMesa | |
68 : public AcceleratedSurfaceContainerLinux { | |
69 public: | |
70 explicit AcceleratedSurfaceContainerLinuxOSMesa(const gfx::Size& size); | |
71 | |
72 virtual bool Initialize(uint64* surface_id) OVERRIDE; | |
73 | |
74 // TextureGL implementation | |
75 virtual void Draw(const ui::TextureDrawParams& params, | |
76 const gfx::Rect& clip_bounds_in_texture) OVERRIDE; | |
77 | |
78 // Some implementations of this class use shared memory, this gives the handle | |
79 // to the shared buffer, which is part of the surface container. | |
80 // When shared memory is not used, this will return | |
81 // TransportDIB::DefaultHandleValue(). | |
82 virtual TransportDIB::Handle Handle() const OVERRIDE; | |
83 | |
84 private: | |
85 virtual ~AcceleratedSurfaceContainerLinuxOSMesa(); | |
86 | |
87 scoped_ptr<TransportDIB> shared_mem_; | |
88 | |
89 DISALLOW_COPY_AND_ASSIGN(AcceleratedSurfaceContainerLinuxOSMesa); | |
90 }; | |
91 | |
92 class ScopedPtrXFree { | |
93 public: | |
94 void operator()(void* x) const { | |
95 ::XFree(x); | |
96 } | |
97 }; | |
98 | |
99 // static | |
100 base::LazyInstance<GLXFBConfig> AcceleratedSurfaceContainerLinuxGLX::fbconfig_( | |
101 base::LINKER_INITIALIZED); | |
102 | |
103 AcceleratedSurfaceContainerLinuxEGL::AcceleratedSurfaceContainerLinuxEGL( | |
104 const gfx::Size& size) | |
105 : AcceleratedSurfaceContainerLinux(size), | |
106 image_(NULL) { | |
107 } | |
108 | |
109 bool AcceleratedSurfaceContainerLinuxEGL::Initialize(uint64* surface_id) { | |
110 ui::SharedResources* instance = ui::SharedResources::GetInstance(); | |
111 DCHECK(instance); | |
112 instance->MakeSharedContextCurrent(); | |
113 | |
114 image_ = eglCreateImageKHR( | |
115 gfx::GLSurfaceEGL::GetHardwareDisplay(), EGL_NO_CONTEXT, | |
116 EGL_NATIVE_PIXMAP_KHR, reinterpret_cast<void*>(*surface_id), NULL); | |
117 | |
118 glGenTextures(1, &texture_id_); | |
119 glBindTexture(GL_TEXTURE_2D, texture_id_); | |
120 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
121 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
122 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
123 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
124 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image_); | |
125 glFlush(); | |
126 | |
127 return true; | |
128 } | |
129 | |
130 AcceleratedSurfaceContainerLinuxEGL::~AcceleratedSurfaceContainerLinuxEGL() { | |
131 ui::SharedResources* instance = ui::SharedResources::GetInstance(); | |
132 DCHECK(instance); | |
133 instance->MakeSharedContextCurrent(); | |
134 | |
135 eglDestroyImageKHR(gfx::GLSurfaceEGL::GetHardwareDisplay(), image_); | |
136 glFlush(); | |
137 } | |
138 | |
139 void AcceleratedSurfaceContainerLinuxEGL::Draw( | |
140 const ui::TextureDrawParams& params, | |
141 const gfx::Rect& clip_bounds_in_texture) { | |
142 ui::SharedResources* instance = ui::SharedResources::GetInstance(); | |
143 DCHECK(instance); | |
144 | |
145 ui::TextureDrawParams modified_params = params; | |
146 modified_params.vertically_flipped = true; | |
147 | |
148 DrawInternal(*instance->program_no_swizzle(), | |
149 modified_params, | |
150 clip_bounds_in_texture); | |
151 } | |
152 | |
153 AcceleratedSurfaceContainerLinuxGLX::AcceleratedSurfaceContainerLinuxGLX( | |
154 const gfx::Size& size) | |
155 : AcceleratedSurfaceContainerLinux(size), | |
156 pixmap_(0), | |
157 glx_pixmap_(0) { | |
158 } | |
159 | |
160 bool AcceleratedSurfaceContainerLinuxGLX::Initialize(uint64* surface_id) { | |
161 ui::SharedResources* instance = ui::SharedResources::GetInstance(); | |
162 DCHECK(instance); | |
163 instance->MakeSharedContextCurrent(); | |
164 | |
165 if (!AcceleratedSurfaceContainerLinuxGLX::InitializeOneOff()) | |
166 return false; | |
167 | |
168 // Create pixmap from window. | |
169 // We receive a window here rather than a pixmap directly because drivers | |
170 // require (or required) that the pixmap used to create the GL texture be | |
171 // created in the same process as the texture. | |
172 Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); | |
173 pixmap_ = XCompositeNameWindowPixmap(dpy, *surface_id); | |
174 | |
175 // Wrap the pixmap in a GLXPixmap | |
176 const int pixmapAttribs[] = { | |
177 GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, | |
178 GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT, | |
179 0 | |
180 }; | |
181 | |
182 glx_pixmap_ = glXCreatePixmap( | |
183 dpy, fbconfig_.Get(), pixmap_, pixmapAttribs); | |
184 | |
185 // Create texture. | |
186 glGenTextures(1, &texture_id_); | |
187 glBindTexture(GL_TEXTURE_2D, texture_id_); | |
188 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
189 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
190 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
191 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
192 | |
193 return true; | |
194 } | |
195 | |
196 AcceleratedSurfaceContainerLinuxGLX::~AcceleratedSurfaceContainerLinuxGLX() { | |
197 ui::SharedResources* instance = ui::SharedResources::GetInstance(); | |
198 DCHECK(instance); | |
199 instance->MakeSharedContextCurrent(); | |
200 | |
201 Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); | |
202 if (glx_pixmap_) | |
203 glXDestroyGLXPixmap(dpy, glx_pixmap_); | |
204 if (pixmap_) | |
205 XFreePixmap(dpy, pixmap_); | |
206 } | |
207 | |
208 void AcceleratedSurfaceContainerLinuxGLX::Draw( | |
209 const ui::TextureDrawParams& params, | |
210 const gfx::Rect& clip_bounds_in_texture) { | |
211 ui::SharedResources* instance = ui::SharedResources::GetInstance(); | |
212 DCHECK(instance); | |
213 | |
214 Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); | |
215 | |
216 glBindTexture(GL_TEXTURE_2D, texture_id_); | |
217 glXBindTexImageEXT(dpy, glx_pixmap_, GLX_FRONT_LEFT_EXT, NULL); | |
218 DrawInternal(*instance->program_no_swizzle(), | |
219 params, | |
220 clip_bounds_in_texture); | |
221 glXReleaseTexImageEXT(dpy, glx_pixmap_, GLX_FRONT_LEFT_EXT); | |
222 } | |
223 | |
224 // static | |
225 bool AcceleratedSurfaceContainerLinuxGLX::InitializeOneOff() | |
226 { | |
227 static bool initialized = false; | |
228 if (initialized) | |
229 return true; | |
230 | |
231 Display* dpy = gfx::GLSurfaceGLX::GetDisplay(); | |
232 int event_base, error_base; | |
233 if (XCompositeQueryExtension(dpy, &event_base, &error_base)) { | |
234 int major = 0, minor = 2; | |
235 XCompositeQueryVersion(dpy, &major, &minor); | |
236 if (major == 0 && minor < 2) { | |
237 LOG(ERROR) << "Pixmap from window not supported."; | |
238 return false; | |
239 } | |
240 } | |
241 | |
242 // Wrap the pixmap in a GLXPixmap | |
243 int screen = DefaultScreen(dpy); | |
244 XWindowAttributes gwa; | |
245 XGetWindowAttributes(dpy, RootWindow(dpy, screen), &gwa); | |
246 unsigned int visualid = XVisualIDFromVisual(gwa.visual); | |
247 | |
248 int nfbconfigs, config; | |
249 scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> fbconfigs( | |
250 glXGetFBConfigs(dpy, screen, &nfbconfigs)); | |
251 | |
252 for (config = 0; config < nfbconfigs; config++) { | |
253 XVisualInfo* visinfo = glXGetVisualFromFBConfig( | |
254 dpy, fbconfigs.get()[config]); | |
255 if (!visinfo || visinfo->visualid != visualid) | |
256 continue; | |
257 | |
258 int value; | |
259 glXGetFBConfigAttrib(dpy, | |
260 fbconfigs.get()[config], | |
261 GLX_DRAWABLE_TYPE, | |
262 &value); | |
263 if (!(value & GLX_PIXMAP_BIT)) | |
264 continue; | |
265 | |
266 glXGetFBConfigAttrib(dpy, | |
267 fbconfigs.get()[config], | |
268 GLX_BIND_TO_TEXTURE_TARGETS_EXT, | |
269 &value); | |
270 if (!(value & GLX_TEXTURE_2D_BIT_EXT)) | |
271 continue; | |
272 | |
273 glXGetFBConfigAttrib(dpy, | |
274 fbconfigs.get()[config], | |
275 GLX_BIND_TO_TEXTURE_RGB_EXT, | |
276 &value); | |
277 if (value == GL_FALSE) | |
278 continue; | |
279 | |
280 break; | |
281 } | |
282 | |
283 if (config == nfbconfigs) { | |
284 LOG(ERROR) | |
285 << "Could not find configuration suitable for binding a pixmap " | |
286 << "as a texture."; | |
287 return false; | |
288 } | |
289 | |
290 fbconfig_.Get() = fbconfigs.get()[config]; | |
291 | |
292 initialized = true; | |
293 return initialized; | |
294 } | |
295 | |
296 AcceleratedSurfaceContainerLinuxOSMesa::AcceleratedSurfaceContainerLinuxOSMesa( | |
297 const gfx::Size& size) | |
298 : AcceleratedSurfaceContainerLinux(size) { | |
299 } | |
300 | |
301 bool AcceleratedSurfaceContainerLinuxOSMesa::Initialize(uint64* surface_id) { | |
302 static uint32 next_id = 1; | |
303 | |
304 ui::SharedResources* instance = ui::SharedResources::GetInstance(); | |
305 DCHECK(instance); | |
306 instance->MakeSharedContextCurrent(); | |
307 | |
308 // We expect to make the id here, so don't want the other end giving us one | |
309 DCHECK_EQ(*surface_id, static_cast<uint64>(0)); | |
310 | |
311 // It's possible that this ID gneration could clash with IDs from other | |
312 // AcceleratedSurfaceContainerLinux* objects, however we should never have | |
313 // ids active from more than one type at the same time, so we have free | |
314 // reign of the id namespace. | |
315 *surface_id = next_id++; | |
316 | |
317 shared_mem_.reset( | |
318 TransportDIB::Create(size_.GetArea() * 4, // GL_RGBA=4 B/px | |
319 *surface_id)); | |
320 // Create texture. | |
321 glGenTextures(1, &texture_id_); | |
322 glBindTexture(GL_TEXTURE_2D, texture_id_); | |
323 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
324 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
325 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
326 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
327 | |
328 // we generate the ID to be used here. | |
329 return true; | |
330 } | |
331 | |
332 void AcceleratedSurfaceContainerLinuxOSMesa::Draw( | |
333 const ui::TextureDrawParams& params, | |
334 const gfx::Rect& clip_bounds_in_texture) { | |
335 ui::SharedResources* instance = ui::SharedResources::GetInstance(); | |
336 DCHECK(instance); | |
337 | |
338 if (shared_mem_.get()) { | |
339 glBindTexture(GL_TEXTURE_2D, texture_id_); | |
340 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, | |
341 size_.width(), size_.height(), 0, | |
342 GL_RGBA, GL_UNSIGNED_BYTE, shared_mem_->memory()); | |
343 | |
344 DrawInternal(*instance->program_no_swizzle(), | |
345 params, | |
346 clip_bounds_in_texture); | |
347 } | |
348 } | |
349 | |
350 TransportDIB::Handle AcceleratedSurfaceContainerLinuxOSMesa::Handle() const { | |
351 if (shared_mem_.get()) | |
352 return shared_mem_->handle(); | |
353 else | |
354 return TransportDIB::DefaultHandleValue(); | |
355 } | |
356 | |
357 AcceleratedSurfaceContainerLinuxOSMesa:: | |
358 ~AcceleratedSurfaceContainerLinuxOSMesa() { | |
359 } | |
360 | |
361 } // namespace | |
362 | |
363 AcceleratedSurfaceContainerLinux::AcceleratedSurfaceContainerLinux( | |
364 const gfx::Size& size) : TextureGL(size) { | |
365 } | |
366 | |
367 TransportDIB::Handle AcceleratedSurfaceContainerLinux::Handle() const { | |
368 return TransportDIB::DefaultHandleValue(); | |
369 } | |
370 | |
371 // static | |
372 AcceleratedSurfaceContainerLinux* | |
373 AcceleratedSurfaceContainerLinux::CreateAcceleratedSurfaceContainer( | |
374 const gfx::Size& size) { | |
375 switch (gfx::GetGLImplementation()) { | |
376 case gfx::kGLImplementationDesktopGL: | |
377 return new AcceleratedSurfaceContainerLinuxGLX(size); | |
378 case gfx::kGLImplementationEGLGLES2: | |
379 return new AcceleratedSurfaceContainerLinuxEGL(size); | |
380 case gfx::kGLImplementationOSMesaGL: | |
381 return new AcceleratedSurfaceContainerLinuxOSMesa(size); | |
382 default: | |
383 NOTREACHED(); | |
384 return NULL; | |
385 } | |
386 } | |
387 | |
388 void AcceleratedSurfaceContainerLinux::SetCanvas( | |
389 const SkCanvas& canvas, | |
390 const gfx::Point& origin, | |
391 const gfx::Size& overall_size) { | |
392 NOTREACHED(); | |
393 } | |
394 | |
OLD | NEW |