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 "ui/gl/gl_surface.h"
6
7 #include "base/debug/trace_event.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop.h"
11 #include "third_party/mesa/src/include/GL/osmesa.h"
12 #include "ui/gl/gl_bindings.h"
13 #include "ui/gl/gl_implementation.h"
14 #include "ui/gl/gl_surface_egl.h"
15 #include "ui/gl/gl_surface_glx.h"
16 #include "ui/gl/gl_surface_osmesa.h"
17 #include "ui/gl/gl_surface_stub.h"
18
19 namespace gfx {
20
21 namespace {
22 Display* g_osmesa_display;
23 } // namespace
24
25 // This OSMesa GL surface can use XLib to swap the contents of the buffer to a
26 // view.
27 class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa {
28 public:
29 explicit NativeViewGLSurfaceOSMesa(gfx::AcceleratedWidget window);
30
31 static bool InitializeOneOff();
32
33 // Implement a subset of GLSurface.
34 virtual bool Initialize() OVERRIDE;
35 virtual void Destroy() OVERRIDE;
36 virtual bool Resize(const gfx::Size& new_size) OVERRIDE;
37 virtual bool IsOffscreen() OVERRIDE;
38 virtual bool SwapBuffers() OVERRIDE;
39 virtual std::string GetExtensions() OVERRIDE;
40 virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE;
41
42 protected:
43 virtual ~NativeViewGLSurfaceOSMesa();
44
45 private:
46 GC window_graphics_context_;
47 gfx::AcceleratedWidget window_;
48 GC pixmap_graphics_context_;
49 Pixmap pixmap_;
50
51 DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa);
52 };
53
InitializeOneOffInternal()54 bool GLSurface::InitializeOneOffInternal() {
55 switch (GetGLImplementation()) {
56 case kGLImplementationDesktopGL:
57 if (!GLSurfaceGLX::InitializeOneOff()) {
58 LOG(ERROR) << "GLSurfaceGLX::InitializeOneOff failed.";
59 return false;
60 }
61 break;
62 case kGLImplementationOSMesaGL:
63 if (!NativeViewGLSurfaceOSMesa::InitializeOneOff()) {
64 LOG(ERROR) << "NativeViewGLSurfaceOSMesa::InitializeOneOff failed.";
65 return false;
66 }
67 break;
68 case kGLImplementationEGLGLES2:
69 if (!GLSurfaceEGL::InitializeOneOff()) {
70 LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
71 return false;
72 }
73 break;
74 default:
75 break;
76 }
77
78 return true;
79 }
80
NativeViewGLSurfaceOSMesa(gfx::AcceleratedWidget window)81 NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa(
82 gfx::AcceleratedWidget window)
83 : GLSurfaceOSMesa(OSMESA_BGRA, gfx::Size(1, 1)),
84 window_graphics_context_(0),
85 window_(window),
86 pixmap_graphics_context_(0),
87 pixmap_(0) {
88 DCHECK(window);
89 }
90
InitializeOneOff()91 bool NativeViewGLSurfaceOSMesa::InitializeOneOff() {
92 static bool initialized = false;
93 if (initialized)
94 return true;
95
96 g_osmesa_display = base::MessagePumpForUI::GetDefaultXDisplay();
97 if (!g_osmesa_display) {
98 LOG(ERROR) << "XOpenDisplay failed.";
99 return false;
100 }
101
102 initialized = true;
103 return true;
104 }
105
Initialize()106 bool NativeViewGLSurfaceOSMesa::Initialize() {
107 if (!GLSurfaceOSMesa::Initialize())
108 return false;
109
110 window_graphics_context_ = XCreateGC(g_osmesa_display,
111 window_,
112 0,
113 NULL);
114 if (!window_graphics_context_) {
115 LOG(ERROR) << "XCreateGC failed.";
116 Destroy();
117 return false;
118 }
119
120 return true;
121 }
122
Destroy()123 void NativeViewGLSurfaceOSMesa::Destroy() {
124 if (pixmap_graphics_context_) {
125 XFreeGC(g_osmesa_display, pixmap_graphics_context_);
126 pixmap_graphics_context_ = NULL;
127 }
128
129 if (pixmap_) {
130 XFreePixmap(g_osmesa_display, pixmap_);
131 pixmap_ = 0;
132 }
133
134 if (window_graphics_context_) {
135 XFreeGC(g_osmesa_display, window_graphics_context_);
136 window_graphics_context_ = NULL;
137 }
138
139 XSync(g_osmesa_display, False);
140 }
141
Resize(const gfx::Size & new_size)142 bool NativeViewGLSurfaceOSMesa::Resize(const gfx::Size& new_size) {
143 if (!GLSurfaceOSMesa::Resize(new_size))
144 return false;
145
146 XWindowAttributes attributes;
147 if (!XGetWindowAttributes(g_osmesa_display, window_, &attributes)) {
148 LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << ".";
149 return false;
150 }
151
152 // Destroy the previous pixmap and graphics context.
153 if (pixmap_graphics_context_) {
154 XFreeGC(g_osmesa_display, pixmap_graphics_context_);
155 pixmap_graphics_context_ = NULL;
156 }
157 if (pixmap_) {
158 XFreePixmap(g_osmesa_display, pixmap_);
159 pixmap_ = 0;
160 }
161
162 // Recreate a pixmap to hold the frame.
163 pixmap_ = XCreatePixmap(g_osmesa_display,
164 window_,
165 new_size.width(),
166 new_size.height(),
167 attributes.depth);
168 if (!pixmap_) {
169 LOG(ERROR) << "XCreatePixmap failed.";
170 return false;
171 }
172
173 // Recreate a graphics context for the pixmap.
174 pixmap_graphics_context_ = XCreateGC(g_osmesa_display, pixmap_, 0, NULL);
175 if (!pixmap_graphics_context_) {
176 LOG(ERROR) << "XCreateGC failed";
177 return false;
178 }
179
180 return true;
181 }
182
IsOffscreen()183 bool NativeViewGLSurfaceOSMesa::IsOffscreen() {
184 return false;
185 }
186
SwapBuffers()187 bool NativeViewGLSurfaceOSMesa::SwapBuffers() {
188 gfx::Size size = GetSize();
189
190 XWindowAttributes attributes;
191 if (!XGetWindowAttributes(g_osmesa_display, window_, &attributes)) {
192 LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << ".";
193 return false;
194 }
195
196 // Copy the frame into the pixmap.
197 gfx::PutARGBImage(g_osmesa_display,
198 attributes.visual,
199 attributes.depth,
200 pixmap_,
201 pixmap_graphics_context_,
202 static_cast<const uint8*>(GetHandle()),
203 size.width(),
204 size.height());
205
206 // Copy the pixmap to the window.
207 XCopyArea(g_osmesa_display,
208 pixmap_,
209 window_,
210 window_graphics_context_,
211 0, 0,
212 size.width(), size.height(),
213 0, 0);
214
215 return true;
216 }
217
GetExtensions()218 std::string NativeViewGLSurfaceOSMesa::GetExtensions() {
219 std::string extensions = gfx::GLSurfaceOSMesa::GetExtensions();
220 extensions += extensions.empty() ? "" : " ";
221 extensions += "GL_CHROMIUM_post_sub_buffer";
222 return extensions;
223 }
224
PostSubBuffer(int x,int y,int width,int height)225 bool NativeViewGLSurfaceOSMesa::PostSubBuffer(
226 int x, int y, int width, int height) {
227 gfx::Size size = GetSize();
228
229 // Move (0,0) from lower-left to upper-left
230 y = size.height() - y - height;
231
232 XWindowAttributes attributes;
233 if (!XGetWindowAttributes(g_osmesa_display, window_, &attributes)) {
234 LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << ".";
235 return false;
236 }
237
238 // Copy the frame into the pixmap.
239 gfx::PutARGBImage(g_osmesa_display,
240 attributes.visual,
241 attributes.depth,
242 pixmap_,
243 pixmap_graphics_context_,
244 static_cast<const uint8*>(GetHandle()),
245 size.width(),
246 size.height(),
247 x, y,
248 x, y,
249 width,
250 height);
251
252 // Copy the pixmap to the window.
253 XCopyArea(g_osmesa_display,
254 pixmap_,
255 window_,
256 window_graphics_context_,
257 x, y,
258 width, height,
259 x, y);
260
261 return true;
262 }
263
~NativeViewGLSurfaceOSMesa()264 NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() {
265 Destroy();
266 }
267
CreateViewGLSurface(gfx::AcceleratedWidget window)268 scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
269 gfx::AcceleratedWidget window) {
270 TRACE_EVENT0("gpu", "GLSurface::CreateViewGLSurface");
271 switch (GetGLImplementation()) {
272 case kGLImplementationOSMesaGL: {
273 scoped_refptr<GLSurface> surface(
274 new NativeViewGLSurfaceOSMesa(window));
275 if (!surface->Initialize())
276 return NULL;
277
278 return surface;
279 }
280 case kGLImplementationDesktopGL: {
281 scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceGLX(window));
282 if (!surface->Initialize())
283 return NULL;
284
285 return surface;
286 }
287 case kGLImplementationEGLGLES2: {
288 scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceEGL(window));
289 if (!surface->Initialize())
290 return NULL;
291
292 return surface;
293 }
294 case kGLImplementationMockGL:
295 return new GLSurfaceStub;
296 default:
297 NOTREACHED();
298 return NULL;
299 }
300 }
301
CreateOffscreenGLSurface(const gfx::Size & size)302 scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
303 const gfx::Size& size) {
304 TRACE_EVENT0("gpu", "GLSurface::CreateOffscreenGLSurface");
305 switch (GetGLImplementation()) {
306 case kGLImplementationOSMesaGL: {
307 scoped_refptr<GLSurface> surface(new GLSurfaceOSMesa(OSMESA_RGBA,
308 size));
309 if (!surface->Initialize())
310 return NULL;
311
312 return surface;
313 }
314 case kGLImplementationDesktopGL: {
315 scoped_refptr<GLSurface> surface(new PbufferGLSurfaceGLX(size));
316 if (!surface->Initialize())
317 return NULL;
318
319 return surface;
320 }
321 case kGLImplementationEGLGLES2: {
322 scoped_refptr<GLSurface> surface(new PbufferGLSurfaceEGL(size));
323 if (!surface->Initialize())
324 return NULL;
325
326 return surface;
327 }
328 case kGLImplementationMockGL:
329 return new GLSurfaceStub;
330 default:
331 NOTREACHED();
332 return NULL;
333 }
334 }
335
336 } // namespace gfx
337