|  | /* | 
|  | *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include "test/linux/glx_renderer.h" | 
|  |  | 
|  | #include <X11/Xlib.h> | 
|  | #include <X11/Xutil.h> | 
|  | #include <stdlib.h> | 
|  |  | 
|  | namespace webrtc { | 
|  | namespace test { | 
|  |  | 
|  | GlxRenderer::GlxRenderer(size_t width, size_t height) | 
|  | : width_(width), height_(height), display_(NULL), context_(NULL) { | 
|  | RTC_DCHECK_GT(width, 0); | 
|  | RTC_DCHECK_GT(height, 0); | 
|  | } | 
|  |  | 
|  | GlxRenderer::~GlxRenderer() { | 
|  | Destroy(); | 
|  | } | 
|  |  | 
|  | bool GlxRenderer::Init(const char* window_title) { | 
|  | if ((display_ = XOpenDisplay(NULL)) == NULL) { | 
|  | Destroy(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | int screen = DefaultScreen(display_); | 
|  |  | 
|  | XVisualInfo* vi; | 
|  | int attr_list[] = { | 
|  | GLX_DOUBLEBUFFER, GLX_RGBA, GLX_RED_SIZE,   4,  GLX_GREEN_SIZE, 4, | 
|  | GLX_BLUE_SIZE,    4,        GLX_DEPTH_SIZE, 16, None, | 
|  | }; | 
|  |  | 
|  | if ((vi = glXChooseVisual(display_, screen, attr_list)) == NULL) { | 
|  | Destroy(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | context_ = glXCreateContext(display_, vi, 0, true); | 
|  | if (context_ == NULL) { | 
|  | Destroy(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | XSetWindowAttributes window_attributes; | 
|  | window_attributes.colormap = XCreateColormap( | 
|  | display_, RootWindow(display_, vi->screen), vi->visual, AllocNone); | 
|  | window_attributes.border_pixel = 0; | 
|  | window_attributes.event_mask = StructureNotifyMask | ExposureMask; | 
|  | window_ = XCreateWindow(display_, RootWindow(display_, vi->screen), 0, 0, | 
|  | width_, height_, 0, vi->depth, InputOutput, | 
|  | vi->visual, CWBorderPixel | CWColormap | CWEventMask, | 
|  | &window_attributes); | 
|  | XFree(vi); | 
|  |  | 
|  | XSetStandardProperties(display_, window_, window_title, window_title, None, | 
|  | NULL, 0, NULL); | 
|  |  | 
|  | Atom wm_delete = XInternAtom(display_, "WM_DELETE_WINDOW", True); | 
|  | if (wm_delete != None) { | 
|  | XSetWMProtocols(display_, window_, &wm_delete, 1); | 
|  | } | 
|  |  | 
|  | XMapRaised(display_, window_); | 
|  |  | 
|  | if (!glXMakeCurrent(display_, window_, context_)) { | 
|  | Destroy(); | 
|  | return false; | 
|  | } | 
|  | GlRenderer::Init(); | 
|  | if (!glXMakeCurrent(display_, None, NULL)) { | 
|  | Destroy(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | Resize(width_, height_); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void GlxRenderer::Destroy() { | 
|  | if (context_ != NULL) { | 
|  | glXMakeCurrent(display_, window_, context_); | 
|  | GlRenderer::Destroy(); | 
|  | glXMakeCurrent(display_, None, NULL); | 
|  | glXDestroyContext(display_, context_); | 
|  | context_ = NULL; | 
|  | } | 
|  |  | 
|  | if (display_ != NULL) { | 
|  | XCloseDisplay(display_); | 
|  | display_ = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | GlxRenderer* GlxRenderer::Create(const char* window_title, | 
|  | size_t width, | 
|  | size_t height) { | 
|  | GlxRenderer* glx_renderer = new GlxRenderer(width, height); | 
|  | if (!glx_renderer->Init(window_title)) { | 
|  | // TODO(pbos): Add GLX-failed warning here? | 
|  | delete glx_renderer; | 
|  | return NULL; | 
|  | } | 
|  | return glx_renderer; | 
|  | } | 
|  |  | 
|  | void GlxRenderer::Resize(size_t width, size_t height) { | 
|  | width_ = width; | 
|  | height_ = height; | 
|  | if (!glXMakeCurrent(display_, window_, context_)) { | 
|  | abort(); | 
|  | } | 
|  | GlRenderer::ResizeViewport(width_, height_); | 
|  | if (!glXMakeCurrent(display_, None, NULL)) { | 
|  | abort(); | 
|  | } | 
|  |  | 
|  | XSizeHints* size_hints = XAllocSizeHints(); | 
|  | if (size_hints == NULL) { | 
|  | abort(); | 
|  | } | 
|  | size_hints->flags = PAspect; | 
|  | size_hints->min_aspect.x = size_hints->max_aspect.x = width_; | 
|  | size_hints->min_aspect.y = size_hints->max_aspect.y = height_; | 
|  | XSetWMNormalHints(display_, window_, size_hints); | 
|  | XFree(size_hints); | 
|  |  | 
|  | XWindowChanges wc; | 
|  | wc.width = static_cast<int>(width); | 
|  | wc.height = static_cast<int>(height); | 
|  | XConfigureWindow(display_, window_, CWWidth | CWHeight, &wc); | 
|  | } | 
|  |  | 
|  | void GlxRenderer::OnFrame(const webrtc::VideoFrame& frame) { | 
|  | if (static_cast<size_t>(frame.width()) != width_ || | 
|  | static_cast<size_t>(frame.height()) != height_) { | 
|  | Resize(static_cast<size_t>(frame.width()), | 
|  | static_cast<size_t>(frame.height())); | 
|  | } | 
|  |  | 
|  | XEvent event; | 
|  | if (!glXMakeCurrent(display_, window_, context_)) { | 
|  | abort(); | 
|  | } | 
|  | while (XPending(display_)) { | 
|  | XNextEvent(display_, &event); | 
|  | switch (event.type) { | 
|  | case ConfigureNotify: | 
|  | GlRenderer::ResizeViewport(event.xconfigure.width, | 
|  | event.xconfigure.height); | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | GlRenderer::OnFrame(frame); | 
|  | glXSwapBuffers(display_, window_); | 
|  |  | 
|  | if (!glXMakeCurrent(display_, None, NULL)) { | 
|  | abort(); | 
|  | } | 
|  | } | 
|  | }  // namespace test | 
|  | }  // namespace webrtc |