summaryrefslogtreecommitdiff
path: root/chromium/ui/gl/glx_util.cc
blob: c7c17d68b3406575d31d4e821c09281b145c13dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gl/glx_util.h"

#include "base/compiler_specific.h"
#include "base/logging.h"
#include "ui/gfx/x/future.h"
#include "ui/gfx/x/glx.h"
#include "ui/gl/gl_bindings.h"

namespace gl {

namespace {

x11::Glx::FbConfig GetConfigForWindow(x11::Connection* conn,
                                      x11::Window window) {
  x11::VisualId visual;
  if (auto attrs = conn->GetWindowAttributes({window}).Sync()) {
    visual = attrs->visual;
  } else {
    LOG(ERROR) << "GetWindowAttributes failed for window "
               << static_cast<uint32_t>(window) << ".";
    return {};
  }

  if (auto configs =
          conn->glx()
              .GetFBConfigs({static_cast<uint32_t>(conn->DefaultScreenId())})
              .Sync()) {
    // The returned property_list is a table consisting of
    // 2 * num_FB_configs * num_properties uint32_t's.  Each entry in the table
    // is a key-value pair.  For example, if we have 2 FB configs and 3
    // properties, then the table would be laid out as such:
    //
    // k(c, p) = key for c'th config of p'th property
    // v(c, p) = value for c'th config of p'th property
    //
    // | k(1, 1) | v(1, 1) | k(1, 2) | v(1, 2) | k(1, 3) | v(1, 3) |
    // | k(2, 1) | v(2, 1) | k(2, 2) | v(2, 2) | k(2, 3) | v(2, 3) |
    auto cfgs = configs->num_FB_configs;
    auto props = configs->num_properties;
    for (size_t cfg = 0; cfg < cfgs; cfg++) {
      x11::Glx::FbConfig fb_config{};
      bool found = false;
      for (size_t prop = 0; prop < props; prop++) {
        size_t i = 2 * cfg * props + 2 * prop;
        auto key = configs->property_list[i];
        auto value = configs->property_list[i + 1];
        if (key == GLX_VISUAL_ID && value == static_cast<uint32_t>(visual))
          found = true;
        else if (key == GLX_FBCONFIG_ID)
          fb_config = static_cast<x11::Glx::FbConfig>(value);
      }
      if (found)
        return fb_config;
    }
  } else {
    LOG(ERROR) << "GetFBConfigs failed.";
    return {};
  }
  return {};
}

}  // namespace

GLXFBConfig GetFbConfigForWindow(x11::Connection* connection,
                                 x11::Window window) {
  return GetGlxFbConfigForXProtoFbConfig(
      connection, GetConfigForWindow(connection, window));
}

GLXFBConfig GetGlxFbConfigForXProtoFbConfig(x11::Connection* connection,
                                            x11::Glx::FbConfig xproto_config) {
  if (xproto_config == x11::Glx::FbConfig{})
    return nullptr;
  int attrib_list[] = {GLX_FBCONFIG_ID, static_cast<int>(xproto_config), 0};
  int nitems = 0;
  GLXFBConfig* glx_configs =
      glXChooseFBConfig(connection->GetXlibDisplay(),
                        connection->DefaultScreenId(), attrib_list, &nitems);
  if (!glx_configs)
    return nullptr;
  GLXFBConfig glx_config = glx_configs[0];
  x11::XlibFree(glx_configs);
  return glx_config;
}

}  // namespace gl