blob: 4a40e4da273550599293c260c98dbcea8b6d3a80 [file] [log] [blame]
// 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/base/x/x11_util.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/x11_window_event_manager.h"
#include "ui/gfx/x/xproto.h"
#include "ui/gfx/x/xproto_util.h"
namespace gpu {
// static
std::unique_ptr<VulkanSurfaceX11> VulkanSurfaceX11::Create(
VkInstance vk_instance,
x11::Window parent_window) {
auto* connection = x11::Connection::Get();
auto geometry = connection->GetGeometry({parent_window}).Sync();
if (!geometry) {
LOG(ERROR) << "GetGeometry failed for window "
<< static_cast<uint32_t>(parent_window) << ".";
return nullptr;
}
auto window = connection->GenerateId<x11::Window>();
connection->CreateWindow(x11::CreateWindowRequest{
.wid = window,
.parent = parent_window,
.width = geometry->width,
.height = geometry->height,
.c_class = x11::WindowClass::InputOutput,
});
if (connection->MapWindow({window}).Sync().error) {
LOG(ERROR) << "Failed to create or map window.";
return nullptr;
}
// Flush the connection, otherwise other Vulkan WSI calls may fail with some
// drivers.
connection->Flush();
VkSurfaceKHR vk_surface;
const VkXcbSurfaceCreateInfoKHR surface_create_info = {
.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
.connection = connection->GetXlibDisplay().GetXcbConnection(),
.window = static_cast<xcb_window_t>(window),
};
VkResult result = vkCreateXcbSurfaceKHR(vk_instance, &surface_create_info,
nullptr, &vk_surface);
if (VK_SUCCESS != result) {
DLOG(ERROR) << "vkCreateXcbSurfaceKHR() failed: " << result;
return nullptr;
}
return std::make_unique<VulkanSurfaceX11>(vk_instance, vk_surface,
parent_window, window);
}
VulkanSurfaceX11::VulkanSurfaceX11(VkInstance vk_instance,
VkSurfaceKHR vk_surface,
x11::Window parent_window,
x11::Window window)
: VulkanSurface(vk_instance,
static_cast<gfx::AcceleratedWidget>(window),
vk_surface,
false /* use_protected_memory */),
parent_window_(parent_window),
window_(window),
event_selector_(std::make_unique<x11::XScopedEventSelector>(
window,
x11::EventMask::Exposure)) {
x11::Connection::Get()->AddEventObserver(this);
}
VulkanSurfaceX11::~VulkanSurfaceX11() {
x11::Connection::Get()->RemoveEventObserver(this);
}
void VulkanSurfaceX11::Destroy() {
VulkanSurface::Destroy();
event_selector_.reset();
if (window_ != x11::Window::None) {
auto* connection = x11::Connection::Get();
connection->DestroyWindow({window_});
window_ = x11::Window::None;
connection->Flush();
}
}
bool VulkanSurfaceX11::Reshape(const gfx::Size& size,
gfx::OverlayTransform pre_transform) {
DCHECK_EQ(pre_transform, gfx::OVERLAY_TRANSFORM_NONE);
auto* connection = x11::Connection::Get();
connection->ConfigureWindow(x11::ConfigureWindowRequest{
.window = window_, .width = size.width(), .height = size.height()});
connection->Flush();
return VulkanSurface::Reshape(size, pre_transform);
}
void VulkanSurfaceX11::OnEvent(const x11::Event& event) {
auto* expose = event.As<x11::ExposeEvent>();
if (!expose || expose->window != window_)
return;
x11::ExposeEvent forwarded_event = *expose;
forwarded_event.window = parent_window_;
x11::SendEvent(forwarded_event, parent_window_, x11::EventMask::Exposure);
x11::Connection::Get()->Flush();
}
} // namespace gpu