summaryrefslogtreecommitdiff
path: root/chromium/gpu/vulkan/x/vulkan_surface_x11.cc
blob: 3bb675440cfa97fe1d58af0e13fdafa13405fbf6 (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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// Copyright 2019 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 "gpu/vulkan/x/vulkan_surface_x11.h"

#include "base/logging.h"
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "ui/events/platform/x11/x11_event_source.h"

namespace gpu {

class VulkanSurfaceX11::ExposeEventForwarder : public ui::XEventDispatcher {
 public:
  explicit ExposeEventForwarder(VulkanSurfaceX11* surface) : surface_(surface) {
    if (auto* event_source = ui::X11EventSource::GetInstance()) {
      XSelectInput(gfx::GetXDisplay(), surface_->window_, ExposureMask);
      event_source->AddXEventDispatcher(this);
    }
  }

  ~ExposeEventForwarder() override {
    if (auto* event_source = ui::X11EventSource::GetInstance())
      event_source->RemoveXEventDispatcher(this);
  }

  // ui::XEventDispatcher:
  bool DispatchXEvent(XEvent* xevent) override {
    if (!surface_->CanDispatchXEvent(xevent))
      return false;
    surface_->ForwardXExposeEvent(xevent);
    return true;
  }

 private:
  VulkanSurfaceX11* const surface_;
  DISALLOW_COPY_AND_ASSIGN(ExposeEventForwarder);
};

// static
std::unique_ptr<VulkanSurfaceX11> VulkanSurfaceX11::Create(
    VkInstance vk_instance,
    Window parent_window) {
  XDisplay* display = gfx::GetXDisplay();
  XWindowAttributes attributes;
  if (!XGetWindowAttributes(display, parent_window, &attributes)) {
    LOG(ERROR) << "XGetWindowAttributes failed for window " << parent_window
               << ".";
    return nullptr;
  }
  Window window = XCreateWindow(display, parent_window, 0, 0, attributes.width,
                                attributes.height, 0, CopyFromParent,
                                InputOutput, CopyFromParent, 0, nullptr);
  if (!window) {
    LOG(ERROR) << "XCreateWindow failed.";
    return nullptr;
  }
  XMapWindow(display, window);

  VkSurfaceKHR vk_surface;
  VkXlibSurfaceCreateInfoKHR surface_create_info = {
      VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR};
  surface_create_info.dpy = display;
  surface_create_info.window = window;
  VkResult result = vkCreateXlibSurfaceKHR(vk_instance, &surface_create_info,
                                           nullptr, &vk_surface);
  if (VK_SUCCESS != result) {
    DLOG(ERROR) << "vkCreateXlibSurfaceKHR() failed: " << result;
    return nullptr;
  }
  return std::make_unique<VulkanSurfaceX11>(vk_instance, vk_surface,
                                            parent_window, window);
}

VulkanSurfaceX11::VulkanSurfaceX11(VkInstance vk_instance,
                                   VkSurfaceKHR vk_surface,
                                   Window parent_window,
                                   Window window)
    : VulkanSurface(vk_instance,
                    window,
                    vk_surface,
                    false /* use_protected_memory */),
      parent_window_(parent_window),
      window_(window),
      expose_event_forwarder_(new ExposeEventForwarder(this)) {}

VulkanSurfaceX11::~VulkanSurfaceX11() {}

// VulkanSurface:
bool VulkanSurfaceX11::Reshape(const gfx::Size& size,
                               gfx::OverlayTransform pre_transform) {
  DCHECK_EQ(pre_transform, gfx::OVERLAY_TRANSFORM_NONE);

  XResizeWindow(gfx::GetXDisplay(), window_, size.width(), size.height());
  return VulkanSurface::Reshape(size, pre_transform);
}

bool VulkanSurfaceX11::CanDispatchXEvent(const XEvent* event) {
  return event->type == Expose && event->xexpose.window == window_;
}

void VulkanSurfaceX11::ForwardXExposeEvent(const XEvent* event) {
  XEvent forwarded_event = *event;
  forwarded_event.xexpose.window = parent_window_;
  XSendEvent(gfx::GetXDisplay(), parent_window_, False, ExposureMask,
             &forwarded_event);
  XFlush(gfx::GetXDisplay());
}

}  // namespace gpu