xref: /aosp_15_r20/external/webrtc/test/linux/glx_renderer.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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