1 /*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "test/linux/glx_renderer.h"
12
13 #include <X11/Xlib.h>
14 #include <X11/Xutil.h>
15 #include <stdlib.h>
16
17 namespace webrtc {
18 namespace test {
19
GlxRenderer(size_t width,size_t height)20 GlxRenderer::GlxRenderer(size_t width, size_t height)
21 : width_(width), height_(height), display_(NULL), context_(NULL) {
22 RTC_DCHECK_GT(width, 0);
23 RTC_DCHECK_GT(height, 0);
24 }
25
~GlxRenderer()26 GlxRenderer::~GlxRenderer() {
27 Destroy();
28 }
29
Init(const char * window_title)30 bool GlxRenderer::Init(const char* window_title) {
31 if ((display_ = XOpenDisplay(NULL)) == NULL) {
32 Destroy();
33 return false;
34 }
35
36 int screen = DefaultScreen(display_);
37
38 XVisualInfo* vi;
39 int attr_list[] = {
40 GLX_DOUBLEBUFFER, GLX_RGBA, GLX_RED_SIZE, 4, GLX_GREEN_SIZE, 4,
41 GLX_BLUE_SIZE, 4, GLX_DEPTH_SIZE, 16, None,
42 };
43
44 if ((vi = glXChooseVisual(display_, screen, attr_list)) == NULL) {
45 Destroy();
46 return false;
47 }
48
49 context_ = glXCreateContext(display_, vi, 0, true);
50 if (context_ == NULL) {
51 Destroy();
52 return false;
53 }
54
55 XSetWindowAttributes window_attributes;
56 window_attributes.colormap = XCreateColormap(
57 display_, RootWindow(display_, vi->screen), vi->visual, AllocNone);
58 window_attributes.border_pixel = 0;
59 window_attributes.event_mask = StructureNotifyMask | ExposureMask;
60 window_ = XCreateWindow(display_, RootWindow(display_, vi->screen), 0, 0,
61 width_, height_, 0, vi->depth, InputOutput,
62 vi->visual, CWBorderPixel | CWColormap | CWEventMask,
63 &window_attributes);
64 XFree(vi);
65
66 XSetStandardProperties(display_, window_, window_title, window_title, None,
67 NULL, 0, NULL);
68
69 Atom wm_delete = XInternAtom(display_, "WM_DELETE_WINDOW", True);
70 if (wm_delete != None) {
71 XSetWMProtocols(display_, window_, &wm_delete, 1);
72 }
73
74 XMapRaised(display_, window_);
75
76 if (!glXMakeCurrent(display_, window_, context_)) {
77 Destroy();
78 return false;
79 }
80 GlRenderer::Init();
81 if (!glXMakeCurrent(display_, None, NULL)) {
82 Destroy();
83 return false;
84 }
85
86 Resize(width_, height_);
87 return true;
88 }
89
Destroy()90 void GlxRenderer::Destroy() {
91 if (context_ != NULL) {
92 glXMakeCurrent(display_, window_, context_);
93 GlRenderer::Destroy();
94 glXMakeCurrent(display_, None, NULL);
95 glXDestroyContext(display_, context_);
96 context_ = NULL;
97 }
98
99 if (display_ != NULL) {
100 XCloseDisplay(display_);
101 display_ = NULL;
102 }
103 }
104
Create(const char * window_title,size_t width,size_t height)105 GlxRenderer* GlxRenderer::Create(const char* window_title,
106 size_t width,
107 size_t height) {
108 GlxRenderer* glx_renderer = new GlxRenderer(width, height);
109 if (!glx_renderer->Init(window_title)) {
110 // TODO(pbos): Add GLX-failed warning here?
111 delete glx_renderer;
112 return NULL;
113 }
114 return glx_renderer;
115 }
116
Resize(size_t width,size_t height)117 void GlxRenderer::Resize(size_t width, size_t height) {
118 width_ = width;
119 height_ = height;
120 if (!glXMakeCurrent(display_, window_, context_)) {
121 abort();
122 }
123 GlRenderer::ResizeViewport(width_, height_);
124 if (!glXMakeCurrent(display_, None, NULL)) {
125 abort();
126 }
127
128 XSizeHints* size_hints = XAllocSizeHints();
129 if (size_hints == NULL) {
130 abort();
131 }
132 size_hints->flags = PAspect;
133 size_hints->min_aspect.x = size_hints->max_aspect.x = width_;
134 size_hints->min_aspect.y = size_hints->max_aspect.y = height_;
135 XSetWMNormalHints(display_, window_, size_hints);
136 XFree(size_hints);
137
138 XWindowChanges wc;
139 wc.width = static_cast<int>(width);
140 wc.height = static_cast<int>(height);
141 XConfigureWindow(display_, window_, CWWidth | CWHeight, &wc);
142 }
143
OnFrame(const webrtc::VideoFrame & frame)144 void GlxRenderer::OnFrame(const webrtc::VideoFrame& frame) {
145 if (static_cast<size_t>(frame.width()) != width_ ||
146 static_cast<size_t>(frame.height()) != height_) {
147 Resize(static_cast<size_t>(frame.width()),
148 static_cast<size_t>(frame.height()));
149 }
150
151 XEvent event;
152 if (!glXMakeCurrent(display_, window_, context_)) {
153 abort();
154 }
155 while (XPending(display_)) {
156 XNextEvent(display_, &event);
157 switch (event.type) {
158 case ConfigureNotify:
159 GlRenderer::ResizeViewport(event.xconfigure.width,
160 event.xconfigure.height);
161 break;
162 default:
163 break;
164 }
165 }
166
167 GlRenderer::OnFrame(frame);
168 glXSwapBuffers(display_, window_);
169
170 if (!glXMakeCurrent(display_, None, NULL)) {
171 abort();
172 }
173 }
174 } // namespace test
175 } // namespace webrtc
176