0

Implement GpuMemoryBuffers for EGL and GLX

Adds GMB support for Linux/X11. ANGLE support will be added in
followup(s). For now, support on EGL/GLX is enabled when
--enable-native-gpu-memory-buffers is passed.

Main code additions:
* GbmSupportX11: ui/gfx/linux/gbm_support_x11.*
  - Uses DRI3 to get an authenticated DRM fd. Creates a GbmDevice
    with it.
* GLImageGLXNativePixmap: ui/gl/gl_image_glx_native_pixmap.*
  - Subclasses GlImageGLX.  Uses DRI3 to get a GLX pixmap from a
    dma-buf.
* ui/gl/gl_visual_picker_glx.*
  - Figures out which GLXFBConfigs should be used for corresponding
    gfx::BufferFormats.  Only BGR(A) formats are supported by GLX.

GMB support used to be routed through gpu::GpuMemoryBufferSupport,
which is basically just a switch statement over the various
gfx::BufferFormats and gfx::BufferUsages. With X11, GMB support needs
to be determined at runtime, and in the GPU process (since it depends
on the singleton GbmDevice and the GL implementation), so GMB support
is put into gpu::GPUInfo, similar to how we're already doing with
visual IDs.

BUG=1031269

Change-Id: Ie254e6c5646073be0cb76d549c115be274e4ef46
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1984712
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Reviewed-by: Martin Barbella <mbarbella@chromium.org>
Reviewed-by: Mark Pearson <mpearson@chromium.org>
Reviewed-by: Jonathan Backer <backer@chromium.org>
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Reviewed-by: kylechar <kylechar@chromium.org>
Reviewed-by: Robert Kroeger <rjkroege@chromium.org>
Cr-Commit-Position: refs/heads/master@{#736698}
This commit is contained in:
Tom Anderson
2020-01-30 03:19:16 +00:00
committed by Commit Bot
parent 839c13c6f2
commit ff8d22e551
53 changed files with 899 additions and 249 deletions

@ -38,6 +38,7 @@ config("x11") {
"X11",
"X11-xcb",
"xcb",
"xcb-dri3",
"Xcomposite",
"Xcursor",
"Xdamage",

@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/process_memory_dump.h"
#include "gpu/ipc/common/gpu_memory_buffer_impl.h"
@ -44,9 +45,12 @@ HostGpuMemoryBufferManager::HostGpuMemoryBufferManager(
: gpu_service_provider_(gpu_service_provider),
client_id_(client_id),
gpu_memory_buffer_support_(std::move(gpu_memory_buffer_support)),
native_configurations_(gpu::GetNativeGpuMemoryBufferConfigurations(
gpu_memory_buffer_support_.get())),
task_runner_(std::move(task_runner)) {
#if !defined(USE_X11)
native_configurations_ = gpu::GetNativeGpuMemoryBufferConfigurations(
gpu_memory_buffer_support_.get());
native_configurations_initialized_.Signal();
#endif
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
this, "HostGpuMemoryBufferManager", task_runner_);
}
@ -161,6 +165,10 @@ bool HostGpuMemoryBufferManager::IsNativeGpuMemoryBufferConfiguration(
gfx::BufferFormat format,
gfx::BufferUsage usage) const {
DCHECK(task_runner_->BelongsToCurrentThread());
{
base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
native_configurations_initialized_.Wait();
}
return native_configurations_.find(std::make_pair(format, usage)) !=
native_configurations_.end();
}
@ -230,6 +238,19 @@ bool HostGpuMemoryBufferManager::OnMemoryDump(
return true;
}
void HostGpuMemoryBufferManager::SetNativeConfigurations(
gpu::GpuMemoryBufferConfigurationSet native_configurations) {
// Must not be done on the task runner thread to avoid deadlock.
DCHECK(!task_runner_->BelongsToCurrentThread());
if (native_configurations_initialized_.IsSignaled()) {
// The configurations are set on GPU initialization and should not change.
DCHECK(native_configurations_ == native_configurations);
} else {
native_configurations_ = native_configurations;
native_configurations_initialized_.Signal();
}
}
mojom::GpuService* HostGpuMemoryBufferManager::GetGpuService() {
DCHECK(task_runner_->BelongsToCurrentThread());

@ -67,6 +67,7 @@ class VIZ_HOST_EXPORT HostGpuMemoryBufferManager
gpu::SurfaceHandle surface_handle,
base::OnceCallback<void(gfx::GpuMemoryBufferHandle)> callback);
// This method will block until the initial GPUInfo is received.
bool IsNativeGpuMemoryBufferConfiguration(gfx::BufferFormat format,
gfx::BufferUsage usage) const;
@ -83,7 +84,14 @@ class VIZ_HOST_EXPORT HostGpuMemoryBufferManager
bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) override;
protected:
// Must be called from a thread other than |task_runner_|'s thread.
void SetNativeConfigurations(
gpu::GpuMemoryBufferConfigurationSet native_configurations);
private:
friend class HostGpuMemoryBufferManagerTest;
struct PendingBufferInfo {
PendingBufferInfo();
PendingBufferInfo(PendingBufferInfo&&);
@ -132,7 +140,9 @@ class VIZ_HOST_EXPORT HostGpuMemoryBufferManager
std::unique_ptr<gpu::GpuMemoryBufferSupport> gpu_memory_buffer_support_;
const gpu::GpuMemoryBufferConfigurationSet native_configurations_;
gpu::GpuMemoryBufferConfigurationSet native_configurations_;
mutable base::WaitableEvent native_configurations_initialized_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
base::WeakPtr<HostGpuMemoryBufferManager> weak_ptr_;
base::WeakPtrFactory<HostGpuMemoryBufferManager> weak_factory_{this};

@ -229,6 +229,10 @@ class HostGpuMemoryBufferManagerTest : public ::testing::Test {
std::move(gpu_service_provider), 1,
std::move(gpu_memory_buffer_support),
base::ThreadTaskRunnerHandle::Get());
#if defined(USE_X11)
// X11 requires GPU process initialization to determine GMB support.
gpu_memory_buffer_manager_->native_configurations_initialized_.Signal();
#endif
}
// Not all platforms support native configurations (currently only Windows,

@ -2277,6 +2277,10 @@ jumbo_source_set("browser") {
"//ui/events/platform/x11",
"//ui/gfx/x",
]
sources += [
"gpu/gpu_memory_buffer_manager_singleton_x11.cc",
"gpu/gpu_memory_buffer_manager_singleton_x11.h",
]
}
if (use_pangocairo) {

@ -33,6 +33,7 @@
#include "base/power_monitor/power_monitor_device_source.h"
#include "base/process/process_metrics.h"
#include "base/run_loop.h"
#include "base/scoped_observer.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
@ -441,21 +442,23 @@ class GpuDataManagerVisualProxy : public GpuDataManagerObserver {
public:
explicit GpuDataManagerVisualProxy(GpuDataManagerImpl* gpu_data_manager)
: gpu_data_manager_(gpu_data_manager) {
gpu_data_manager_->AddObserver(this);
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless))
scoped_observer_.Add(gpu_data_manager_);
}
~GpuDataManagerVisualProxy() override {
gpu_data_manager_->RemoveObserver(this);
}
~GpuDataManagerVisualProxy() override = default;
void OnGpuInfoUpdate() override {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless))
return;
void OnGpuInfoUpdate() override { OnUpdate(); }
void OnGpuExtraInfoUpdate() override { OnUpdate(); }
private:
void OnUpdate() {
gpu::GPUInfo gpu_info = gpu_data_manager_->GetGPUInfo();
gpu::GpuExtraInfo gpu_extra_info = gpu_data_manager_->GetGpuExtraInfo();
if (!ui::XVisualManager::GetInstance()->OnGPUInfoChanged(
gpu_info.software_rendering ||
!gpu_data_manager_->GpuAccessAllowed(nullptr),
gpu_info.system_visual, gpu_info.rgba_visual)) {
gpu_extra_info.system_visual, gpu_extra_info.rgba_visual)) {
// The GPU process sent back bad visuals, which should never happen.
auto* gpu_process_host =
GpuProcessHost::Get(GPU_PROCESS_KIND_SANDBOXED, false);
@ -464,9 +467,11 @@ class GpuDataManagerVisualProxy : public GpuDataManagerObserver {
}
}
private:
GpuDataManagerImpl* gpu_data_manager_;
ScopedObserver<GpuDataManagerImpl, GpuDataManagerObserver> scoped_observer_{
this};
DISALLOW_COPY_AND_ASSIGN(GpuDataManagerVisualProxy);
};

@ -42,16 +42,31 @@
#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
#endif
#if defined(USE_X11)
#include "content/browser/gpu/gpu_memory_buffer_manager_singleton_x11.h" // nogncheck
#endif
namespace content {
#if defined(OS_ANDROID)
namespace {
#if defined(OS_ANDROID)
void TimedOut() {
LOG(FATAL) << "Timed out waiting for GPU channel.";
}
} // namespace
#endif // OS_ANDROID
GpuMemoryBufferManagerSingleton* CreateGpuMemoryBufferManagerSingleton(
int gpu_client_id) {
#if defined(USE_X11)
return new GpuMemoryBufferManagerSingletonX11(gpu_client_id);
#else
return new GpuMemoryBufferManagerSingleton(gpu_client_id);
#endif
}
} // namespace
BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = nullptr;
class BrowserGpuChannelHostFactory::EstablishRequest
@ -259,7 +274,7 @@ BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
gpu_client_tracing_id_(
memory_instrumentation::mojom::kServiceTracingProcessId),
gpu_memory_buffer_manager_(
new GpuMemoryBufferManagerSingleton(gpu_client_id_)) {
CreateGpuMemoryBufferManagerSingleton(gpu_client_id_)) {
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableGpuShaderDiskCache)) {
DCHECK(GetContentClient());

@ -877,6 +877,8 @@ void GpuDataManagerImplPrivate::UpdateGpuFeatureInfo(
void GpuDataManagerImplPrivate::UpdateGpuExtraInfo(
const gpu::GpuExtraInfo& gpu_extra_info) {
gpu_extra_info_ = gpu_extra_info;
observer_list_->Notify(FROM_HERE,
&GpuDataManagerObserver::OnGpuExtraInfoUpdate);
}
gpu::GpuFeatureInfo GpuDataManagerImplPrivate::GetGpuFeatureInfo() const {
@ -957,10 +959,14 @@ void GpuDataManagerImplPrivate::UpdateGpuPreferences(
// GpuMemoryBuffer if this is not native, see https://crbug.com/791676.
if (auto* gpu_memory_buffer_manager =
GpuMemoryBufferManagerSingleton::GetInstance()) {
// On X11, we do not know GpuMemoryBuffer configuration support until
// receiving the initial GPUInfo.
#if !defined(USE_X11)
gpu_preferences->disable_biplanar_gpu_memory_buffers_for_video_frames =
!gpu_memory_buffer_manager->IsNativeGpuMemoryBufferConfiguration(
gfx::BufferFormat::YUV_420_BIPLANAR,
gfx::BufferUsage::GPU_READ_CPU_READ_WRITE);
#endif
}
gpu_preferences->gpu_program_cache_size =

@ -143,7 +143,8 @@ std::string GPUDeviceToString(const gpu::GPUInfo::GPUDevice& gpu) {
std::unique_ptr<base::ListValue> BasicGpuInfoAsListValue(
const gpu::GPUInfo& gpu_info,
const gpu::GpuFeatureInfo& gpu_feature_info) {
const gpu::GpuFeatureInfo& gpu_feature_info,
const gpu::GpuExtraInfo& gpu_extra_info) {
const gpu::GPUInfo::GPUDevice& active_gpu = gpu_info.active_gpu();
auto basic_info = std::make_unique<base::ListValue>();
basic_info->Append(NewDescriptionValuePair(
@ -264,6 +265,10 @@ std::unique_ptr<base::ListValue> BasicGpuInfoAsListValue(
"Compositing manager",
ui::IsCompositingManagerPresent() ? "Yes" : "No"));
}
basic_info->Append(NewDescriptionValuePair(
"System visual ID", base::NumberToString(gpu_extra_info.system_visual)));
basic_info->Append(NewDescriptionValuePair(
"RGBA visual ID", base::NumberToString(gpu_extra_info.rgba_visual)));
#endif
std::string direct_rendering_version;
if (gpu_info.direct_rendering_version == "1") {
@ -290,13 +295,6 @@ std::unique_ptr<base::ListValue> BasicGpuInfoAsListValue(
"GPU process crash count",
std::make_unique<base::Value>(GpuProcessHost::GetGpuCrashCount())));
#if defined(USE_X11)
basic_info->Append(NewDescriptionValuePair(
"System visual ID", base::NumberToString(gpu_info.system_visual)));
basic_info->Append(NewDescriptionValuePair(
"RGBA visual ID", base::NumberToString(gpu_info.rgba_visual)));
#endif
std::string buffer_formats;
for (int i = 0; i <= static_cast<int>(gfx::BufferFormat::LAST); ++i) {
const gfx::BufferFormat buffer_format = static_cast<gfx::BufferFormat>(i);
@ -321,7 +319,10 @@ std::unique_ptr<base::DictionaryValue> GpuInfoAsDictionaryValue() {
const gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
const gpu::GpuFeatureInfo gpu_feature_info =
GpuDataManagerImpl::GetInstance()->GetGpuFeatureInfo();
auto basic_info = BasicGpuInfoAsListValue(gpu_info, gpu_feature_info);
const gpu::GpuExtraInfo gpu_extra_info =
GpuDataManagerImpl::GetInstance()->GetGpuExtraInfo();
auto basic_info =
BasicGpuInfoAsListValue(gpu_info, gpu_feature_info, gpu_extra_info);
info->Set("basicInfo", std::move(basic_info));
#if defined(OS_WIN)
@ -353,22 +354,32 @@ std::unique_ptr<base::ListValue> CompositorInfo() {
return compositor_info;
}
std::unique_ptr<base::ListValue> GpuMemoryBufferInfo() {
std::unique_ptr<base::ListValue> GpuMemoryBufferInfo(
const gpu::GpuExtraInfo& gpu_extra_info) {
auto gpu_memory_buffer_info = std::make_unique<base::ListValue>();
gpu::GpuMemoryBufferSupport gpu_memory_buffer_support;
#if defined(USE_X11)
const auto& native_configurations =
gpu_extra_info.gpu_memory_buffer_support_x11;
#else
const auto native_configurations =
gpu::GetNativeGpuMemoryBufferConfigurations(&gpu_memory_buffer_support);
#endif
for (size_t format = 0;
format < static_cast<size_t>(gfx::BufferFormat::LAST) + 1; format++) {
std::string native_usage_support;
for (size_t usage = 0;
usage < static_cast<size_t>(gfx::BufferUsage::LAST) + 1; usage++) {
if (base::Contains(
native_configurations,
std::make_pair(static_cast<gfx::BufferFormat>(format),
static_cast<gfx::BufferUsage>(usage)))) {
#if defined(USE_X11)
gfx::BufferUsageAndFormat element{static_cast<gfx::BufferUsage>(usage),
static_cast<gfx::BufferFormat>(format)};
#else
auto element = std::make_pair(static_cast<gfx::BufferFormat>(format),
static_cast<gfx::BufferUsage>(usage));
#endif
if (base::Contains(native_configurations, element)) {
native_usage_support = base::StringPrintf(
"%s%s %s", native_usage_support.c_str(),
native_usage_support.empty() ? "" : ",",
@ -686,6 +697,8 @@ std::unique_ptr<base::ListValue> GpuMessageHandler::OnRequestLogMessages(
void GpuMessageHandler::OnGpuInfoUpdate() {
// Get GPU Info.
const gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
const gpu::GpuExtraInfo gpu_extra_info =
GpuDataManagerImpl::GetInstance()->GetGpuExtraInfo();
auto gpu_info_val = GpuInfoAsDictionaryValue();
// Add in blacklisting features
@ -716,12 +729,13 @@ void GpuMessageHandler::OnGpuInfoUpdate() {
const gpu::GpuFeatureInfo gpu_feature_info_for_hardware_gpu =
GpuDataManagerImpl::GetInstance()->GetGpuFeatureInfoForHardwareGpu();
auto gpu_info_for_hardware_gpu_val = BasicGpuInfoAsListValue(
gpu_info_for_hardware_gpu, gpu_feature_info_for_hardware_gpu);
gpu_info_for_hardware_gpu, gpu_feature_info_for_hardware_gpu,
gpu::GpuExtraInfo{});
gpu_info_val->Set("basicInfoForHardwareGpu",
std::move(gpu_info_for_hardware_gpu_val));
}
gpu_info_val->Set("compositorInfo", CompositorInfo());
gpu_info_val->Set("gpuMemoryBufferInfo", GpuMemoryBufferInfo());
gpu_info_val->Set("gpuMemoryBufferInfo", GpuMemoryBufferInfo(gpu_extra_info));
gpu_info_val->Set("displayInfo", getDisplayInfo());
gpu_info_val->Set("videoAcceleratorsInfo", GetVideoAcceleratorsInfo());
gpu_info_val->Set("ANGLEFeatures", GetANGLEFeatures());

@ -0,0 +1,31 @@
// 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 "content/browser/gpu/gpu_memory_buffer_manager_singleton_x11.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
namespace content {
GpuMemoryBufferManagerSingletonX11::GpuMemoryBufferManagerSingletonX11(
int client_id)
: GpuMemoryBufferManagerSingleton(client_id),
gpu_data_manager_impl_(GpuDataManagerImpl::GetInstance()) {
gpu_data_manager_impl_->AddObserver(this);
}
GpuMemoryBufferManagerSingletonX11::~GpuMemoryBufferManagerSingletonX11() {
gpu_data_manager_impl_->RemoveObserver(this);
}
void GpuMemoryBufferManagerSingletonX11::OnGpuExtraInfoUpdate() {
have_gpu_info_ = true;
gpu::GpuMemoryBufferConfigurationSet configs;
for (const auto& config : gpu_data_manager_impl_->GetGpuExtraInfo()
.gpu_memory_buffer_support_x11) {
configs.insert(std::make_pair(config.format, config.usage));
}
SetNativeConfigurations(std::move(configs));
}
} // namespace content

@ -0,0 +1,40 @@
// 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.
#ifndef CONTENT_BROWSER_GPU_GPU_MEMORY_BUFFER_MANAGER_SINGLETON_X11_H_
#define CONTENT_BROWSER_GPU_GPU_MEMORY_BUFFER_MANAGER_SINGLETON_X11_H_
#include "content/browser/gpu/gpu_memory_buffer_manager_singleton.h"
#include "content/public/browser/gpu_data_manager_observer.h"
namespace content {
class GpuDataManagerImpl;
// With X11, the supported buffer configurations can only be determined at
// runtime, with help from the GPU process. This class adds functionality for
// updating the supported configuration list when new GPUInfo is received.
class GpuMemoryBufferManagerSingletonX11
: public GpuMemoryBufferManagerSingleton,
public GpuDataManagerObserver {
public:
explicit GpuMemoryBufferManagerSingletonX11(int client_id);
~GpuMemoryBufferManagerSingletonX11() override;
GpuMemoryBufferManagerSingletonX11(
const GpuMemoryBufferManagerSingletonX11&) = delete;
GpuMemoryBufferManagerSingletonX11& operator=(
const GpuMemoryBufferManagerSingletonX11&) = delete;
private:
// GpuDataManagerObserver:
void OnGpuExtraInfoUpdate() override;
bool have_gpu_info_ = false;
GpuDataManagerImpl* gpu_data_manager_impl_ = nullptr;
};
} // namespace content
#endif // CONTENT_BROWSER_GPU_GPU_MEMORY_BUFFER_MANAGER_SINGLETON_X11_H_

@ -113,6 +113,7 @@ target(link_target_type, "gpu_sources") {
if (use_x11) {
deps += [
"//ui/events/platform/x11",
"//ui/gfx/linux:gpu_memory_buffer_support_x11",
"//ui/gfx/x",
]
}

@ -18,6 +18,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
#include "base/task/post_task.h"
#include "base/task/single_thread_task_executor.h"
#include "base/threading/platform_thread.h"
#include "base/timer/hi_res_timer_manager.h"
@ -77,9 +78,10 @@
#endif
#if defined(USE_X11)
#include "ui/base/x/x11_util.h" // nogncheck
#include "ui/gfx/x/x11_connection.h" // nogncheck
#include "ui/gfx/x/x11_switches.h" // nogncheck
#include "ui/base/x/x11_util.h" // nogncheck
#include "ui/gfx/linux/gpu_memory_buffer_support_x11.h" // nogncheck
#include "ui/gfx/x/x11_connection.h" // nogncheck
#include "ui/gfx/x/x11_switches.h" // nogncheck
#endif
#if defined(OS_LINUX)
@ -371,6 +373,16 @@ int GpuMain(const MainFunctionParams& parameters) {
GpuProcess gpu_process(io_thread_priority);
#endif
#if defined(USE_X11)
// ui::GbmDevice() takes >50ms with amdgpu, so kick off
// GpuMemoryBufferSupportX11 creation on another thread now.
base::PostTask(
FROM_HERE, base::BindOnce([]() {
SCOPED_UMA_HISTOGRAM_TIMER("Linux.X11.GbmSupportX11CreationTime");
ui::GpuMemoryBufferSupportX11::GetInstance();
}));
#endif
auto* client = GetContentClient()->gpu();
if (client)
client->PostIOThreadCreated(gpu_process.io_task_runner());

@ -0,0 +1,3 @@
per-file *gpu*=backer@chromium.org
per-file *gpu*=kbr@chromium.org
per-file *gpu*=zmo@chromium.org

@ -14,9 +14,12 @@ namespace content {
// can un-register with GpuDataManager::RemoveObserver.
class CONTENT_EXPORT GpuDataManagerObserver {
public:
// Called for any observers whenever there is a GPU info update.
// Called for any observers whenever there is a GPUInfo update.
virtual void OnGpuInfoUpdate() {}
// Called for any observers whenever there is a GpuExtraInfo update.
virtual void OnGpuExtraInfoUpdate() {}
// Called for any observer when the GPU process crashed.
virtual void OnGpuProcessCrashed(base::TerminationStatus exit_code) {}

@ -22,6 +22,7 @@
#include "gpu/config/gpu_finch_features.h"
#include "gpu/config/gpu_switches.h"
#include "media/media_buildflags.h"
#include "ui/gfx/switches.h"
namespace {
@ -106,6 +107,9 @@ const gpu::GpuPreferences GetGpuPreferencesFromCommandLine() {
gpu_preferences.enable_android_surface_control =
ShouldEnableAndroidSurfaceControl(*command_line);
gpu_preferences.enable_native_gpu_memory_buffers =
command_line->HasSwitch(switches::kEnableNativeGpuMemoryBuffers);
// Some of these preferences are set or adjusted in
// GpuDataManagerImplPrivate::AppendGpuCommandLine.
return gpu_preferences;

@ -72,7 +72,7 @@ GPU_EXPORT uint32_t GetBufferTextureTarget(gfx::BufferUsage usage,
GPU_EXPORT bool NativeBufferNeedsPlatformSpecificTextureTarget(
gfx::BufferFormat format) {
#if defined(USE_OZONE)
#if defined(USE_OZONE) || defined(OS_LINUX)
// Always use GL_TEXTURE_2D as the target for RGB textures.
// https://crbug.com/916728
if (format == gfx::BufferFormat::R_8 || format == gfx::BufferFormat::RG_88 ||

@ -213,4 +213,7 @@ jumbo_source_set("config_sources") {
if (is_linux || is_mac) {
deps += [ "//third_party/angle:angle_gpu_info_util" ]
}
if (use_x11) {
deps += [ "//ui/gfx/linux:gpu_memory_buffer_support_x11" ]
}
}

@ -9,6 +9,11 @@
#include <vector>
#include "gpu/gpu_export.h"
#include "ui/gfx/buffer_types.h"
#if defined(USE_X11)
typedef unsigned long VisualID;
#endif
namespace gpu {
@ -52,6 +57,13 @@ struct GPU_EXPORT GpuExtraInfo {
// List of the currently available ANGLE features. May be empty if not
// applicable.
ANGLEFeatures angle_features;
#if defined(USE_X11)
VisualID system_visual = 0;
VisualID rgba_visual = 0;
std::vector<gfx::BufferUsageAndFormat> gpu_memory_buffer_support_x11;
#endif
};
} // namespace gpu

@ -184,10 +184,6 @@ GPUInfo::GPUInfo()
in_process_gpu(true),
passthrough_cmd_decoder(false),
jpeg_decode_accelerator_supported(false),
#if defined(USE_X11)
system_visual(0),
rgba_visual(0),
#endif
oop_rasterization_supported(false),
subpixel_font_rendering(true) {
}
@ -259,11 +255,6 @@ void GPUInfo::EnumerateFields(Enumerator* enumerator) const {
ImageDecodeAcceleratorSupportedProfiles
image_decode_accelerator_supported_profiles;
#if defined(USE_X11)
VisualID system_visual;
VisualID rgba_visual;
#endif
bool oop_rasterization_supported;
bool subpixel_font_rendering;
@ -334,10 +325,6 @@ void GPUInfo::EnumerateFields(Enumerator* enumerator) const {
jpeg_decode_accelerator_supported);
for (const auto& profile : image_decode_accelerator_supported_profiles)
EnumerateImageDecodeAcceleratorSupportedProfile(profile, enumerator);
#if defined(USE_X11)
enumerator->AddInt64("systemVisual", system_visual);
enumerator->AddInt64("rgbaVisual", rgba_visual);
#endif
enumerator->AddBool("oopRasterizationSupported", oop_rasterization_supported);
enumerator->AddBool("subpixelFontRendering", subpixel_font_rendering);
#if BUILDFLAG(ENABLE_VULKAN)

@ -23,10 +23,6 @@
#include "gpu/vulkan/buildflags.h"
#include "ui/gfx/geometry/size.h"
#if defined(USE_X11)
typedef unsigned long VisualID;
#endif
#if BUILDFLAG(ENABLE_VULKAN)
#include "gpu/config/vulkan_info.h"
#endif
@ -355,11 +351,6 @@ struct GPU_EXPORT GPUInfo {
ImageDecodeAcceleratorSupportedProfiles
image_decode_accelerator_supported_profiles;
#if defined(USE_X11)
VisualID system_visual;
VisualID rgba_visual;
#endif
bool oop_rasterization_supported;
bool subpixel_font_rendering;

@ -35,6 +35,8 @@
#include "ui/gl/init/gl_factory.h"
#if defined(USE_X11)
#include "ui/gfx/linux/gpu_memory_buffer_support_x11.h"
#include "ui/gfx/switches.h"
#include "ui/gl/gl_visual_picker_glx.h"
#endif
@ -260,18 +262,11 @@ bool CollectGraphicsInfoGL(GPUInfo* gpu_info) {
gfx::HasExtension(extension_set, "GL_KHR_robustness") ||
gfx::HasExtension(extension_set, "GL_ARB_robustness");
if (supports_robustness) {
glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
glGetIntegerv(
GL_RESET_NOTIFICATION_STRATEGY_ARB,
reinterpret_cast<GLint*>(&gpu_info->gl_reset_notification_strategy));
}
#if defined(USE_X11)
if (gl::GetGLImplementation() == gl::kGLImplementationDesktopGL) {
gl::GLVisualPickerGLX* visual_picker = gl::GLVisualPickerGLX::GetInstance();
gpu_info->system_visual = visual_picker->system_visual().visualid;
gpu_info->rgba_visual = visual_picker->rgba_visual().visualid;
}
#endif
// Unconditionally check oop raster status regardless of preferences
// so that finch trials can turn it on.
gpu_info->oop_rasterization_supported = SupportsOOPRaster(gl_info);
@ -403,7 +398,8 @@ void CollectGraphicsInfoForTesting(GPUInfo* gpu_info) {
#endif // OS_ANDROID
}
bool CollectGpuExtraInfo(GpuExtraInfo* gpu_extra_info) {
bool CollectGpuExtraInfo(GpuExtraInfo* gpu_extra_info,
const GpuPreferences& prefs) {
// Populate the list of ANGLE features by querying the functions exposed by
// EGL_ANGLE_feature_control if it's available.
if (gl::GLSurfaceEGL::IsANGLEFeatureControlSupported()) {
@ -428,6 +424,39 @@ bool CollectGpuExtraInfo(GpuExtraInfo* gpu_extra_info) {
}
}
#if defined(USE_X11)
// Create the GLVisualPickerGLX singleton now while the GbmSupportX11
// singleton is busy being created on another thread.
gl::GLVisualPickerGLX* visual_picker;
if (gl::GetGLImplementation() == gl::kGLImplementationDesktopGL)
visual_picker = gl::GLVisualPickerGLX::GetInstance();
// TODO(https://crbug.com/1031269): Enable by default.
if (prefs.enable_native_gpu_memory_buffers) {
gpu_extra_info->gpu_memory_buffer_support_x11 =
ui::GpuMemoryBufferSupportX11::GetInstance()->supported_configs();
}
if (gl::GetGLImplementation() == gl::kGLImplementationDesktopGL) {
gpu_extra_info->system_visual = visual_picker->system_visual().visualid;
gpu_extra_info->rgba_visual = visual_picker->rgba_visual().visualid;
// With GLX, only BGR(A) buffer formats are supported. EGL does not have
// this restriction.
gpu_extra_info->gpu_memory_buffer_support_x11.erase(
std::remove_if(gpu_extra_info->gpu_memory_buffer_support_x11.begin(),
gpu_extra_info->gpu_memory_buffer_support_x11.end(),
[&](gfx::BufferUsageAndFormat usage_and_format) {
return !visual_picker->GetFbConfigForFormat(
usage_and_format.format);
}),
gpu_extra_info->gpu_memory_buffer_support_x11.end());
} else if (gl::GetGLImplementation() == gl::kGLImplementationEGLANGLE) {
// ANGLE does not yet support EGL_EXT_image_dma_buf_import[_modifiers].
gpu_extra_info->gpu_memory_buffer_support_x11.clear();
}
#endif
return true;
}

@ -10,6 +10,7 @@
#include "build/build_config.h"
#include "gpu/config/gpu_extra_info.h"
#include "gpu/config/gpu_info.h"
#include "gpu/config/gpu_preferences.h"
#include "gpu/gpu_export.h"
namespace angle {
@ -61,7 +62,8 @@ void FillGPUInfoFromSystemInfo(GPUInfo* gpu_info,
GPU_EXPORT void CollectGraphicsInfoForTesting(GPUInfo* gpu_info);
// Collect Graphics info related to the current process
GPU_EXPORT bool CollectGpuExtraInfo(GpuExtraInfo* gpu_extra_info);
GPU_EXPORT bool CollectGpuExtraInfo(GpuExtraInfo* gpu_extra_info,
const GpuPreferences& prefs);
} // namespace gpu

@ -244,6 +244,12 @@ struct GPU_EXPORT GpuPreferences {
base::MessagePumpType message_pump_type = base::MessagePumpType::DEFAULT;
#endif
// ===================================
// Settings from //ui/gfx/switches.h
// Enable native CPU-mappable GPU memory buffer support on Linux.
bool enable_native_gpu_memory_buffers = false;
// Please update gpu_preferences_unittest.cc when making additions or
// changes to this struct.
};

@ -80,6 +80,8 @@ void CheckGpuPreferencesEqual(GpuPreferences left, GpuPreferences right) {
#if defined(USE_OZONE)
EXPECT_EQ(left.message_pump_type, right.message_pump_type);
#endif
EXPECT_EQ(left.enable_native_gpu_memory_buffers,
right.enable_native_gpu_memory_buffers);
}
} // namespace
@ -170,6 +172,7 @@ TEST(GpuPreferencesTest, EncodeDecode) {
GPU_PREFERENCES_FIELD_ENUM(message_pump_type, base::MessagePumpType::UI,
base::MessagePumpType::UI)
#endif
GPU_PREFERENCES_FIELD(enable_native_gpu_memory_buffers, true);
input_prefs.texture_target_exception_list.emplace_back(
gfx::BufferUsage::SCANOUT, gfx::BufferFormat::RGBA_8888);

@ -216,9 +216,13 @@ mojom("interfaces") {
"//ui/gfx/geometry/mojom",
"//ui/gfx/mojom",
]
enabled_features = []
if (enable_vulkan) {
public_deps += [ ":vulkan_interface" ]
enabled_features = [ "supports_vulkan" ]
enabled_features += [ "supports_vulkan" ]
}
if (use_x11) {
enabled_features += [ "use_x11" ]
}
}

@ -5,6 +5,8 @@
// gpu/config/gpu_extra_info.h
module gpu.mojom;
import "ui/gfx/mojom/buffer_types.mojom";
// gpu::ANGLEFeature
struct ANGLEFeature {
string name;
@ -19,4 +21,11 @@ struct ANGLEFeature {
struct GpuExtraInfo {
// List of features queried from ANGLE
array<ANGLEFeature> angle_features;
[EnableIf=use_x11]
uint64 system_visual;
[EnableIf=use_x11]
uint64 rgba_visual;
[EnableIf=use_x11]
array<gfx.mojom.BufferUsageAndFormat> gpu_memory_buffer_support_x11;
};

@ -3,7 +3,9 @@
// found in the LICENSE file.
#include "gpu/ipc/common/gpu_extra_info_mojom_traits.h"
#include "build/build_config.h"
#include "ui/gfx/mojom/buffer_types_mojom_traits.h"
namespace mojo {
@ -20,7 +22,15 @@ bool StructTraits<gpu::mojom::ANGLEFeatureDataView, gpu::ANGLEFeature>::Read(
bool StructTraits<gpu::mojom::GpuExtraInfoDataView, gpu::GpuExtraInfo>::Read(
gpu::mojom::GpuExtraInfoDataView data,
gpu::GpuExtraInfo* out) {
return data.ReadAngleFeatures(&out->angle_features);
if (!data.ReadAngleFeatures(&out->angle_features))
return false;
#if defined(USE_X11)
out->system_visual = data.system_visual();
out->rgba_visual = data.rgba_visual();
if (!data.ReadGpuMemoryBufferSupportX11(&out->gpu_memory_buffer_support_x11))
return false;
#endif
return true;
}
} // namespace mojo

@ -50,6 +50,21 @@ struct StructTraits<gpu::mojom::GpuExtraInfoDataView, gpu::GpuExtraInfo> {
const gpu::GpuExtraInfo& input) {
return input.angle_features;
}
#if defined(USE_X11)
static uint64_t system_visual(const gpu::GpuExtraInfo& input) {
return input.system_visual;
}
static uint64_t rgba_visual(const gpu::GpuExtraInfo& input) {
return input.rgba_visual;
}
static const std::vector<gfx::BufferUsageAndFormat>&
gpu_memory_buffer_support_x11(const gpu::GpuExtraInfo& input) {
return input.gpu_memory_buffer_support_x11;
}
#endif
};
} // namespace mojo

@ -172,8 +172,6 @@ struct GpuInfo {
array<ImageDecodeAcceleratorSupportedProfile>
image_decode_accelerator_supported_profiles;
uint64 system_visual;
uint64 rgba_visual;
bool oop_rasterization_supported;
bool subpixel_font_rendering;

@ -378,10 +378,6 @@ bool StructTraits<gpu::mojom::GpuInfoDataView, gpu::GPUInfo>::Read(
out->jpeg_decode_accelerator_supported =
data.jpeg_decode_accelerator_supported();
#if defined(USE_X11)
out->system_visual = data.system_visual();
out->rgba_visual = data.rgba_visual();
#endif
out->oop_rasterization_supported = data.oop_rasterization_supported();
out->subpixel_font_rendering = data.subpixel_font_rendering();

@ -10,6 +10,7 @@
#include "gpu/config/gpu_info.h"
#include "gpu/ipc/common/dx_diag_node_mojom_traits.h"
#include "gpu/ipc/common/gpu_info.mojom.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/geometry/mojom/geometry_mojom_traits.h"
namespace mojo {
@ -114,7 +115,7 @@ struct StructTraits<gpu::mojom::VideoDecodeAcceleratorCapabilitiesDataView,
}
static std::vector<gpu::VideoDecodeAcceleratorSupportedProfile>
supported_profiles(const gpu::VideoDecodeAcceleratorCapabilities& input) {
supported_profiles(const gpu::VideoDecodeAcceleratorCapabilities& input) {
return input.supported_profiles;
}
};
@ -374,20 +375,6 @@ struct StructTraits<gpu::mojom::GpuInfoDataView, gpu::GPUInfo> {
return input.image_decode_accelerator_supported_profiles;
}
static uint64_t system_visual(const gpu::GPUInfo& input) {
#if defined(USE_X11)
return input.system_visual;
#endif
return 0;
}
static uint64_t rgba_visual(const gpu::GPUInfo& input) {
#if defined(USE_X11)
return input.rgba_visual;
#endif
return 0;
}
static bool oop_rasterization_supported(const gpu::GPUInfo& input) {
return input.oop_rasterization_supported;
}

@ -102,8 +102,9 @@ TYPED_TEST_P(GpuMemoryBufferImplTest, CreateFromHandle) {
gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE,
};
for (auto usage : usages) {
if (!TestFixture::gpu_memory_buffer_support()->IsConfigurationSupported(
TypeParam::kBufferType, format, usage)) {
if (!TestFixture::gpu_memory_buffer_support()
->IsConfigurationSupportedForTest(TypeParam::kBufferType, format,
usage)) {
continue;
}
@ -142,8 +143,9 @@ TYPED_TEST_P(GpuMemoryBufferImplTest, CreateFromHandleSmallBuffer) {
gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE,
};
for (auto usage : usages) {
if (!TestFixture::gpu_memory_buffer_support()->IsConfigurationSupported(
TypeParam::kBufferType, format, usage)) {
if (!TestFixture::gpu_memory_buffer_support()
->IsConfigurationSupportedForTest(TypeParam::kBufferType, format,
usage)) {
continue;
}
@ -177,9 +179,10 @@ TYPED_TEST_P(GpuMemoryBufferImplTest, Map) {
const gfx::Size kBufferSize(4, 4);
for (auto format : gfx::GetBufferFormatsForTesting()) {
if (!TestFixture::gpu_memory_buffer_support()->IsConfigurationSupported(
TypeParam::kBufferType, format,
gfx::BufferUsage::GPU_READ_CPU_READ_WRITE)) {
if (!TestFixture::gpu_memory_buffer_support()
->IsConfigurationSupportedForTest(
TypeParam::kBufferType, format,
gfx::BufferUsage::GPU_READ_CPU_READ_WRITE)) {
continue;
}
@ -231,9 +234,10 @@ TYPED_TEST_P(GpuMemoryBufferImplTest, PersistentMap) {
const gfx::Size kBufferSize(4, 4);
for (auto format : gfx::GetBufferFormatsForTesting()) {
if (!TestFixture::gpu_memory_buffer_support()->IsConfigurationSupported(
TypeParam::kBufferType, format,
gfx::BufferUsage::GPU_READ_CPU_READ_WRITE)) {
if (!TestFixture::gpu_memory_buffer_support()
->IsConfigurationSupportedForTest(
TypeParam::kBufferType, format,
gfx::BufferUsage::GPU_READ_CPU_READ_WRITE)) {
continue;
}
@ -316,8 +320,9 @@ TYPED_TEST_P(GpuMemoryBufferImplTest, SerializeAndDeserialize) {
gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE,
};
for (auto usage : usages) {
if (!TestFixture::gpu_memory_buffer_support()->IsConfigurationSupported(
TypeParam::kBufferType, format, usage))
if (!TestFixture::gpu_memory_buffer_support()
->IsConfigurationSupportedForTest(TypeParam::kBufferType, format,
usage))
continue;
bool destroyed = false;
@ -363,8 +368,9 @@ TYPED_TEST_P(GpuMemoryBufferImplCreateTest, Create) {
gfx::BufferUsage usage = gfx::BufferUsage::GPU_READ;
for (auto format : gfx::GetBufferFormatsForTesting()) {
if (!TestFixture::gpu_memory_buffer_support()->IsConfigurationSupported(
TypeParam::kBufferType, format, usage))
if (!TestFixture::gpu_memory_buffer_support()
->IsConfigurationSupportedForTest(TypeParam::kBufferType, format,
usage))
continue;
bool destroyed = false;
std::unique_ptr<TypeParam> buffer(TypeParam::Create(

@ -114,8 +114,13 @@ bool GpuMemoryBufferSupport::IsNativeGpuMemoryBufferConfigurationSupported(
#elif defined(USE_OZONE)
return ui::OzonePlatform::GetInstance()->IsNativePixmapConfigSupported(format,
usage);
#elif defined(OS_LINUX)
return false; // TODO(julian.isorce): Add linux support.
#elif defined(USE_X11)
// On X11, GPU memory buffer support can only be determined after GPU
// initialization.
// viz::HostGpuMemoryBufferManager::IsNativeGpuMemoryBufferConfiguration()
// should be used instead.
NOTREACHED();
return false;
#elif defined(OS_WIN)
switch (usage) {
case gfx::BufferUsage::GPU_READ:
@ -138,12 +143,18 @@ bool GpuMemoryBufferSupport::IsNativeGpuMemoryBufferConfigurationSupported(
#endif
}
bool GpuMemoryBufferSupport::IsConfigurationSupported(
bool GpuMemoryBufferSupport::IsConfigurationSupportedForTest(
gfx::GpuMemoryBufferType type,
gfx::BufferFormat format,
gfx::BufferUsage usage) {
if (type == GetNativeGpuMemoryBufferType())
if (type == GetNativeGpuMemoryBufferType()) {
#if defined(USE_X11)
// On X11, we require GPUInfo to determine configuration support.
return false;
#else
return IsNativeGpuMemoryBufferConfigurationSupported(format, usage);
#endif
}
if (type == gfx::SHARED_MEMORY_BUFFER) {
return GpuMemoryBufferImplSharedMemory::IsConfigurationSupported(format,

@ -45,9 +45,9 @@ class GPU_EXPORT GpuMemoryBufferSupport {
#endif
// Returns whether the provided buffer format is supported.
bool IsConfigurationSupported(gfx::GpuMemoryBufferType type,
gfx::BufferFormat format,
gfx::BufferUsage usage);
bool IsConfigurationSupportedForTest(gfx::GpuMemoryBufferType type,
gfx::BufferFormat format,
gfx::BufferUsage usage);
// Creates a GpuMemoryBufferImpl from the given |handle|. |size| and |format|
// should match what was used to allocate the |handle|. |callback|, if

@ -87,4 +87,6 @@ struct GpuPreferences {
[EnableIf=use_ozone]
mojo_base.mojom.MessagePumpType message_pump_type;
bool enable_native_gpu_memory_buffers;
};

@ -178,6 +178,9 @@ struct StructTraits<gpu::mojom::GpuPreferencesDataView, gpu::GpuPreferences> {
return false;
#endif
out->enable_native_gpu_memory_buffers =
prefs.enable_native_gpu_memory_buffers();
return true;
}
@ -347,6 +350,10 @@ struct StructTraits<gpu::mojom::GpuPreferencesDataView, gpu::GpuPreferences> {
return prefs.message_pump_type;
}
#endif
static bool enable_native_gpu_memory_buffers(
const gpu::GpuPreferences& prefs) {
return prefs.enable_native_gpu_memory_buffers;
}
};
} // namespace mojo

@ -178,10 +178,6 @@ TEST_F(StructTraitsTest, GpuInfo) {
const std::vector<gpu::VideoEncodeAcceleratorSupportedProfile>
video_encode_accelerator_supported_profiles;
const bool jpeg_decode_accelerator_supported = true;
#if defined(USE_X11)
const VisualID system_visual = 0x1234;
const VisualID rgba_visual = 0x5678;
#endif
gpu::GPUInfo input;
input.initialization_time = initialization_time;
@ -221,10 +217,6 @@ TEST_F(StructTraitsTest, GpuInfo) {
input.video_encode_accelerator_supported_profiles =
video_encode_accelerator_supported_profiles;
input.jpeg_decode_accelerator_supported = jpeg_decode_accelerator_supported;
#if defined(USE_X11)
input.system_visual = system_visual;
input.rgba_visual = rgba_visual;
#endif
mojo::Remote<mojom::TraitsTestService> remote = GetTraitsTestRemote();
gpu::GPUInfo output;
@ -302,10 +294,6 @@ TEST_F(StructTraitsTest, GpuInfo) {
video_decode_accelerator_capabilities.supported_profiles.size());
EXPECT_EQ(output.video_encode_accelerator_supported_profiles.size(),
video_encode_accelerator_supported_profiles.size());
#if defined(USE_X11)
EXPECT_EQ(system_visual, output.system_visual);
EXPECT_EQ(rgba_visual, output.rgba_visual);
#endif
}
TEST_F(StructTraitsTest, EmptyGpuInfo) {

@ -134,6 +134,7 @@ jumbo_component("service") {
if (use_x11) {
sources += [ "x_util.h" ]
libs += [ "X11" ]
deps += [ "//ui/gfx/linux:gpu_memory_buffer_support_x11" ]
}
if (use_ozone) {
deps += [ "//ui/ozone" ]

@ -409,7 +409,7 @@ bool GpuInit::InitializeAndStartSandbox(base::CommandLine* command_line,
// Collect GPU process info
if (!gl_disabled) {
if (!CollectGpuExtraInfo(&gpu_extra_info_))
if (!CollectGpuExtraInfo(&gpu_extra_info_, gpu_preferences))
return false;
}

@ -15,14 +15,40 @@
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_enums.h"
#include "ui/gl/gl_image_native_pixmap.h"
#include "ui/gl/gl_implementation.h"
#if defined(USE_OZONE)
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/surface_factory_ozone.h"
#endif
#if defined(USE_X11)
#include "ui/gfx/linux/gbm_buffer.h" // nogncheck
#include "ui/gfx/linux/gpu_memory_buffer_support_x11.h" // nogncheck
#include "ui/gl/gl_image_glx_native_pixmap.h" // nogncheck
#endif
namespace gpu {
namespace {
// The boilerplate code to initialize each GLImage that we need is the same, but
// the Initialize() methods are not virtual, so a template is needed.
template <class Image, class Pixmap>
scoped_refptr<Image> CreateImageFromPixmap(const gfx::Size& size,
gfx::BufferFormat format,
scoped_refptr<Pixmap> pixmap) {
auto image = base::MakeRefCounted<Image>(size, format);
if (!image->Initialize(std::move(pixmap))) {
LOG(ERROR) << "Failed to create GLImage " << size.ToString() << ", "
<< gfx::BufferFormatToString(format);
return nullptr;
}
return image;
}
} // namespace
GpuMemoryBufferFactoryNativePixmap::GpuMemoryBufferFactoryNativePixmap()
: GpuMemoryBufferFactoryNativePixmap(nullptr) {}
@ -49,6 +75,18 @@ GpuMemoryBufferFactoryNativePixmap::CreateGpuMemoryBuffer(
usage);
return CreateGpuMemoryBufferFromNativePixmap(id, size, format, usage,
client_id, std::move(pixmap));
#elif defined(USE_X11)
std::unique_ptr<ui::GbmBuffer> buffer =
ui::GpuMemoryBufferSupportX11::GetInstance()->CreateBuffer(format, size,
usage);
if (!buffer)
return gfx::GpuMemoryBufferHandle();
gfx::NativePixmapHandle handle = buffer->ExportHandle();
scoped_refptr<gfx::NativePixmapDmaBuf> pixmap =
base::MakeRefCounted<gfx::NativePixmapDmaBuf>(size, format,
std::move(handle));
return CreateGpuMemoryBufferFromNativePixmap(id, size, format, usage,
client_id, std::move(pixmap));
#else
NOTIMPLEMENTED();
return gfx::GpuMemoryBufferHandle();
@ -72,6 +110,9 @@ void GpuMemoryBufferFactoryNativePixmap::CreateGpuMemoryBufferAsync(
&GpuMemoryBufferFactoryNativePixmap::OnNativePixmapCreated, id,
size, format, usage, client_id, std::move(callback),
weak_factory_.GetWeakPtr()));
#elif defined(USE_X11)
std::move(callback).Run(CreateGpuMemoryBuffer(id, size, format, usage,
client_id, surface_handle));
#else
NOTIMPLEMENTED();
std::move(callback).Run(gfx::GpuMemoryBufferHandle());
@ -131,13 +172,22 @@ GpuMemoryBufferFactoryNativePixmap::CreateImageForGpuMemoryBuffer(
}
}
auto image = base::MakeRefCounted<gl::GLImageNativePixmap>(size, format);
if (!image->Initialize(std::move(pixmap))) {
LOG(ERROR) << "Failed to create GLImage " << size.ToString() << ", "
<< gfx::BufferFormatToString(format);
return nullptr;
switch (gl::GetGLImplementation()) {
case gl::kGLImplementationEGLGLES2:
case gl::kGLImplementationEGLANGLE:
// EGL
return CreateImageFromPixmap<gl::GLImageNativePixmap>(size, format,
pixmap);
#if defined(USE_X11)
case gl::kGLImplementationDesktopGL:
// GLX
return CreateImageFromPixmap<gl::GLImageGLXNativePixmap>(size, format,
pixmap);
#endif
default:
NOTREACHED();
return nullptr;
}
return image;
}
bool GpuMemoryBufferFactoryNativePixmap::SupportsCreateAnonymousImage() const {

@ -68,8 +68,13 @@ TYPED_TEST_P(GpuMemoryBufferFactoryTest, CreateGpuMemoryBuffer) {
gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE,
};
for (auto usage : usages) {
#if defined(USE_X11)
// On X11, we require GPUInfo to determine configuration support.
continue;
#else
if (!support.IsNativeGpuMemoryBufferConfigurationSupported(format, usage))
continue;
#endif
gfx::GpuMemoryBufferHandle handle =
TestFixture::factory_.CreateGpuMemoryBuffer(kBufferId, buffer_size,

@ -65635,6 +65635,15 @@ uploading your change for review.
</summary>
</histogram>
<histogram name="Linux.X11.GbmSupportX11CreationTime" units="ms"
expires_after="2020-11-30">
<owner>thomasanderson@chromium.org</owner>
<owner>rjkroege@chromium.org</owner>
<summary>
The amount of time (ms) to construct the GbmSupportX11 singleton.
</summary>
</histogram>
<histogram name="Linux.X11.ServerRTT" units="microseconds" expires_after="M77">
<owner>thomasanderson@chromium.org</owner>
<summary>

@ -44,3 +44,23 @@ source_set("gbm") {
"//ui/gfx/geometry:geometry",
]
}
if (use_x11) {
component("gpu_memory_buffer_support_x11") {
configs += [ "//build/config/linux:x11" ]
sources = [
"gpu_memory_buffer_support_x11.cc",
"gpu_memory_buffer_support_x11.h",
]
deps = [
":drm",
":gbm",
"//base",
"//skia",
"//ui/gfx:buffer_types",
"//ui/gfx:memory_buffer",
"//ui/gfx/x",
]
defines = [ "IS_GBM_SUPPORT_X11_IMPL" ]
}
}

@ -0,0 +1,151 @@
// 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/gfx/linux/gpu_memory_buffer_support_x11.h"
#include <fcntl.h>
#include <xcb/dri3.h>
#include <xcb/xcb.h>
#include <memory>
#include "base/debug/crash_logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/stl_util.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/buffer_usage_util.h"
#include "ui/gfx/linux/drm_util_linux.h"
#include "ui/gfx/linux/gbm_buffer.h"
#include "ui/gfx/linux/gbm_device.h"
#include "ui/gfx/linux/gbm_util.h"
#include "ui/gfx/linux/gbm_wrapper.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_types.h"
namespace ui {
namespace {
// Obtain an authenticated DRM fd from X11 and create a GbmDevice with it.
std::unique_ptr<ui::GbmDevice> CreateX11GbmDevice() {
XDisplay* display = gfx::GetXDisplay();
// |display| may be nullptr in headless mode.
if (!display)
return nullptr;
xcb_connection_t* connection = XGetXCBConnection(display);
DCHECK(connection);
const auto* dri3_extension = xcb_get_extension_data(connection, &xcb_dri3_id);
if (!dri3_extension || !dri3_extension->present)
return nullptr;
// Let the X11 server know the DRI3 client version. This is required to use
// the DRI3 extension. We don't care about the returned server version because
// we only use features from the original DRI3 interface.
auto version_cookie = xcb_dri3_query_version(
connection, XCB_DRI3_MAJOR_VERSION, XCB_DRI3_MINOR_VERSION);
auto* version_reply =
xcb_dri3_query_version_reply(connection, version_cookie, nullptr);
if (!version_reply)
return nullptr;
free(version_reply);
// Obtain an authenticated DRM fd.
auto open_cookie =
xcb_dri3_open(connection, DefaultRootWindow(display), x11::None);
auto* open_reply = xcb_dri3_open_reply(connection, open_cookie, nullptr);
if (!open_reply)
return nullptr;
if (open_reply->nfd != 1)
return nullptr;
int fd = xcb_dri3_open_reply_fds(connection, open_reply)[0];
free(open_reply);
if (fd < 0)
return nullptr;
if (HANDLE_EINTR(fcntl(fd, F_SETFD, FD_CLOEXEC)) == -1)
return nullptr;
return ui::CreateGbmDevice(fd);
}
std::vector<gfx::BufferUsageAndFormat> CreateSupportedConfigList(
ui::GbmDevice* device) {
if (!device)
return {};
std::vector<gfx::BufferUsageAndFormat> configs;
for (gfx::BufferUsage usage : {
gfx::BufferUsage::GPU_READ,
gfx::BufferUsage::SCANOUT,
gfx::BufferUsage::SCANOUT_CPU_READ_WRITE,
gfx::BufferUsage::GPU_READ_CPU_READ_WRITE,
}) {
for (gfx::BufferFormat format : {
gfx::BufferFormat::R_8,
gfx::BufferFormat::RG_88,
gfx::BufferFormat::RGBA_8888,
gfx::BufferFormat::RGBX_8888,
gfx::BufferFormat::BGRA_8888,
gfx::BufferFormat::BGRX_8888,
gfx::BufferFormat::BGRX_1010102,
// On some Intel setups calling gbm_bo_create() with this format
// results in a crash caused by an integer-divide-by-zero.
// TODO(thomasanderson): Enable this format.
// gfx::BufferFormat::RGBA_1010102,
gfx::BufferFormat::BGR_565,
gfx::BufferFormat::YUV_420_BIPLANAR,
gfx::BufferFormat::YVU_420,
gfx::BufferFormat::P010,
}) {
// At least on mesa/amdgpu, gbm_device_is_format_supported() lies. Test
// format support by creating a buffer directly. Use a 2x2 buffer so that
// YUV420 formats get properly tested.
if (device->CreateBuffer(GetFourCCFormatFromBufferFormat(format),
gfx::Size(2, 2), BufferUsageToGbmFlags(usage))) {
configs.push_back(gfx::BufferUsageAndFormat(usage, format));
}
}
}
return configs;
}
} // namespace
// static
GpuMemoryBufferSupportX11* GpuMemoryBufferSupportX11::GetInstance() {
static base::NoDestructor<GpuMemoryBufferSupportX11> instance;
return instance.get();
}
GpuMemoryBufferSupportX11::GpuMemoryBufferSupportX11()
: device_(CreateX11GbmDevice()),
supported_configs_(CreateSupportedConfigList(device_.get())) {}
GpuMemoryBufferSupportX11::~GpuMemoryBufferSupportX11() = default;
std::unique_ptr<GbmBuffer> GpuMemoryBufferSupportX11::CreateBuffer(
gfx::BufferFormat format,
const gfx::Size& size,
gfx::BufferUsage usage) {
DCHECK(device_);
DCHECK(base::Contains(supported_configs_,
gfx::BufferUsageAndFormat(usage, format)));
static base::debug::CrashKeyString* crash_key_string =
base::debug::AllocateCrashKeyString("buffer_usage_and_format",
base::debug::CrashKeySize::Size64);
std::string buffer_usage_and_format = gfx::BufferFormatToString(format) +
std::string(",") +
gfx::BufferUsageToString(usage);
base::debug::ScopedCrashKeyString scoped_crash_key(
crash_key_string, buffer_usage_and_format.c_str());
return device_->CreateBuffer(GetFourCCFormatFromBufferFormat(format), size,
BufferUsageToGbmFlags(usage));
}
} // namespace ui

@ -0,0 +1,55 @@
// 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.
#ifndef UI_GFX_LINUX_GPU_MEMORY_BUFFER_SUPPORT_X11_H_
#define UI_GFX_LINUX_GPU_MEMORY_BUFFER_SUPPORT_X11_H_
#include <memory>
#include <vector>
#include "base/component_export.h"
#include "base/no_destructor.h"
#include "ui/gfx/buffer_types.h"
namespace gfx {
class Size;
}
namespace ui {
class GbmBuffer;
class GbmDevice;
// Obtains and holds a GbmDevice for creating GbmBuffers. Maintains a list of
// supported buffer configurations.
class COMPONENT_EXPORT(GBM_SUPPORT_X11) GpuMemoryBufferSupportX11 {
public:
static GpuMemoryBufferSupportX11* GetInstance();
std::unique_ptr<GbmBuffer> CreateBuffer(gfx::BufferFormat format,
const gfx::Size& size,
gfx::BufferUsage usage);
~GpuMemoryBufferSupportX11();
GpuMemoryBufferSupportX11(const GpuMemoryBufferSupportX11&) = delete;
GpuMemoryBufferSupportX11& operator=(const GpuMemoryBufferSupportX11&) =
delete;
const std::vector<gfx::BufferUsageAndFormat>& supported_configs() const {
return supported_configs_;
}
private:
friend class base::NoDestructor<GpuMemoryBufferSupportX11>;
GpuMemoryBufferSupportX11();
const std::unique_ptr<GbmDevice> device_;
const std::vector<gfx::BufferUsageAndFormat> supported_configs_;
};
} // namespace ui
#endif // UI_GFX_LINUX_GPU_MEMORY_BUFFER_SUPPORT_X11_H_

@ -280,6 +280,8 @@ jumbo_component("gl") {
"gl_glx_api_implementation.h",
"gl_image_glx.cc",
"gl_image_glx.h",
"gl_image_glx_native_pixmap.cc",
"gl_image_glx_native_pixmap.h",
"gl_surface_glx.cc",
"gl_surface_glx.h",
"gl_visual_picker_glx.cc",

@ -6,18 +6,22 @@
#include "base/logging.h"
#include "ui/gfx/x/x11.h"
#include "ui/gl/buffer_format_utils.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_image_glx.h"
#include "ui/gl/gl_surface_glx.h"
#include "ui/gl/gl_visual_picker_glx.h"
namespace gl {
namespace {
int TextureFormat(unsigned internalformat) {
switch (internalformat) {
case GL_RGB:
int TextureFormat(gfx::BufferFormat format) {
switch (format) {
case gfx::BufferFormat::BGR_565:
case gfx::BufferFormat::BGRX_8888:
case gfx::BufferFormat::BGRX_1010102:
return GLX_TEXTURE_FORMAT_RGB_EXT;
case GL_RGBA:
case gfx::BufferFormat::BGRA_8888:
return GLX_TEXTURE_FORMAT_RGBA_EXT;
default:
NOTREACHED();
@ -25,70 +29,10 @@ int TextureFormat(unsigned internalformat) {
}
}
int BindToTextureFormat(unsigned internalformat) {
switch (internalformat) {
case GL_RGB:
return GLX_BIND_TO_TEXTURE_RGB_EXT;
case GL_RGBA:
return GLX_BIND_TO_TEXTURE_RGBA_EXT;
default:
NOTREACHED();
return 0;
}
}
unsigned PixmapDepth(unsigned internalformat) {
switch (internalformat) {
case GL_RGBA:
return 32u;
case GL_RGB:
return 24u;
default:
NOTREACHED();
return 0u;
}
}
bool ActualPixmapGeometry(XID pixmap, gfx::Size* size, unsigned* depth) {
XID root_return;
int x_return;
int y_return;
unsigned width_return;
unsigned height_return;
unsigned border_width_return;
unsigned depth_return;
if (!XGetGeometry(gfx::GetXDisplay(), pixmap, &root_return, &x_return,
&y_return, &width_return, &height_return,
&border_width_return, &depth_return))
return false;
if (size)
*size = gfx::Size(width_return, height_return);
if (depth)
*depth = depth_return;
return true;
}
unsigned ActualPixmapDepth(XID pixmap) {
unsigned depth;
if (!ActualPixmapGeometry(pixmap, NULL, &depth))
return -1;
return depth;
}
gfx::Size ActualPixmapSize(XID pixmap) {
gfx::Size size;
if (!ActualPixmapGeometry(pixmap, &size, NULL))
return gfx::Size();
return size;
}
} // namespace
GLImageGLX::GLImageGLX(const gfx::Size& size, unsigned internalformat)
: glx_pixmap_(0), size_(size), internalformat_(internalformat) {}
GLImageGLX::GLImageGLX(const gfx::Size& size, gfx::BufferFormat format)
: glx_pixmap_(0), size_(size), format_(format) {}
GLImageGLX::~GLImageGLX() {
if (glx_pixmap_)
@ -96,42 +40,15 @@ GLImageGLX::~GLImageGLX() {
}
bool GLImageGLX::Initialize(XID pixmap) {
if (!GLSurfaceGLX::IsTextureFromPixmapSupported()) {
DVLOG(0) << "GLX_EXT_texture_from_pixmap not supported.";
GLXFBConfig fb_config =
GLVisualPickerGLX::GetInstance()->GetFbConfigForFormat(format_);
if (!fb_config)
return false;
}
if (!ValidFormat(internalformat_)) {
DVLOG(0) << "Invalid format: " << internalformat_;
return false;
}
DCHECK_EQ(PixmapDepth(internalformat_), ActualPixmapDepth(pixmap));
DCHECK_EQ(size_.ToString(), ActualPixmapSize(pixmap).ToString());
int config_attribs[] = {
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
BindToTextureFormat(internalformat_), GL_TRUE,
0};
int num_elements = 0;
gfx::XScopedPtr<GLXFBConfig> config(
glXChooseFBConfig(gfx::GetXDisplay(), DefaultScreen(gfx::GetXDisplay()),
config_attribs, &num_elements));
if (!config.get()) {
DVLOG(0) << "glXChooseFBConfig failed.";
return false;
}
if (!num_elements) {
DVLOG(0) << "glXChooseFBConfig returned 0 elements.";
return false;
}
int pixmap_attribs[] = {GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
GLX_TEXTURE_FORMAT_EXT,
TextureFormat(internalformat_), 0};
glx_pixmap_ = glXCreatePixmap(gfx::GetXDisplay(), *config.get(), pixmap,
pixmap_attribs);
GLX_TEXTURE_FORMAT_EXT, TextureFormat(format_), 0};
glx_pixmap_ =
glXCreatePixmap(gfx::GetXDisplay(), fb_config, pixmap, pixmap_attribs);
if (!glx_pixmap_) {
DVLOG(0) << "glXCreatePixmap failed.";
return false;
@ -144,7 +61,9 @@ gfx::Size GLImageGLX::GetSize() {
return size_;
}
unsigned GLImageGLX::GetInternalFormat() { return internalformat_; }
unsigned GLImageGLX::GetInternalFormat() {
return gl::BufferFormatToGLInternalFormat(format_);
}
unsigned GLImageGLX::GetDataType() {
return GL_UNSIGNED_BYTE;
@ -162,7 +81,8 @@ bool GLImageGLX::BindTexImage(unsigned target) {
if (target != GL_TEXTURE_2D)
return false;
glXBindTexImageEXT(gfx::GetXDisplay(), glx_pixmap_, GLX_FRONT_LEFT_EXT, 0);
glXBindTexImageEXT(gfx::GetXDisplay(), glx_pixmap_, GLX_FRONT_LEFT_EXT,
nullptr);
return true;
}
@ -201,14 +121,4 @@ void GLImageGLX::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
// TODO(ericrk): Implement GLImage OnMemoryDump. crbug.com/514914
}
bool GLImageGLX::ValidFormat(unsigned internalformat) {
switch (internalformat) {
case GL_RGB:
case GL_RGBA:
return true;
default:
return false;
}
}
} // namespace gl

@ -17,7 +17,7 @@ namespace gl {
class GL_EXPORT GLImageGLX : public GLImage {
public:
GLImageGLX(const gfx::Size& size, unsigned internalformat);
GLImageGLX(const gfx::Size& size, gfx::BufferFormat format);
bool Initialize(XID pixmap);
@ -47,12 +47,12 @@ class GL_EXPORT GLImageGLX : public GLImage {
protected:
~GLImageGLX() override;
private:
static bool ValidFormat(unsigned internalformat);
gfx::BufferFormat format() const { return format_; }
private:
XID glx_pixmap_;
const gfx::Size size_;
unsigned internalformat_;
gfx::BufferFormat format_;
DISALLOW_COPY_AND_ASSIGN(GLImageGLX);
};

@ -0,0 +1,88 @@
// 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/gl_image_glx_native_pixmap.h"
#include <xcb/dri3.h>
#include <xcb/xcb.h>
#include "base/posix/eintr_wrapper.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/linux/native_pixmap_dmabuf.h"
#include "ui/gfx/x/x11.h"
#include "ui/gl/buffer_format_utils.h"
#include "ui/gl/gl_bindings.h"
namespace gl {
namespace {
int Depth(gfx::BufferFormat format) {
switch (format) {
case gfx::BufferFormat::BGR_565:
return 16;
case gfx::BufferFormat::BGRX_8888:
return 24;
case gfx::BufferFormat::BGRX_1010102:
// It's unclear why this is 32 instead of 30.
return 32;
case gfx::BufferFormat::BGRA_8888:
return 32;
default:
NOTREACHED();
return 0;
}
}
int Bpp(gfx::BufferFormat format) {
switch (format) {
case gfx::BufferFormat::BGR_565:
return 16;
case gfx::BufferFormat::BGRX_8888:
case gfx::BufferFormat::BGRX_1010102:
case gfx::BufferFormat::BGRA_8888:
return 32;
default:
NOTREACHED();
return 0;
}
}
XID XPixmapFromNativePixmap(const gfx::NativePixmapDmaBuf& native_pixmap,
int depth,
int bpp) {
XDisplay* display = gfx::GetXDisplay();
xcb_connection_t* connection = XGetXCBConnection(display);
int fd = HANDLE_EINTR(dup(native_pixmap.GetDmaBufFd(0)));
if (fd < 0)
return 0;
uint32_t pixmap_id = xcb_generate_id(connection);
xcb_dri3_pixmap_from_buffer(connection, pixmap_id, DefaultRootWindow(display),
native_pixmap.GetDmaBufPlaneSize(0),
native_pixmap.GetBufferSize().width(),
native_pixmap.GetBufferSize().height(),
native_pixmap.GetDmaBufPitch(0), depth, bpp, fd);
return pixmap_id;
}
} // namespace
GLImageGLXNativePixmap::GLImageGLXNativePixmap(const gfx::Size& size,
gfx::BufferFormat format)
: GLImageGLX(size, format) {}
GLImageGLXNativePixmap::~GLImageGLXNativePixmap() = default;
bool GLImageGLXNativePixmap::Initialize(
scoped_refptr<gfx::NativePixmap> pixmap) {
native_pixmap_ = pixmap;
return GLImageGLX::Initialize(XPixmapFromNativePixmap(
*static_cast<gfx::NativePixmapDmaBuf*>(native_pixmap_.get()),
Depth(format()), Bpp(format())));
}
} // namespace gl

@ -0,0 +1,34 @@
// 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.
#ifndef UI_GL_GL_IMAGE_GLX_NATIVE_PIXMAP_H_
#define UI_GL_GL_IMAGE_GLX_NATIVE_PIXMAP_H_
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_pixmap.h"
#include "ui/gl/gl_export.h"
#include "ui/gl/gl_image_glx.h"
namespace gl {
class GL_EXPORT GLImageGLXNativePixmap : public GLImageGLX {
public:
GLImageGLXNativePixmap(const gfx::Size& size, gfx::BufferFormat format);
bool Initialize(scoped_refptr<gfx::NativePixmap> pixmap);
protected:
~GLImageGLXNativePixmap() override;
private:
scoped_refptr<gfx::NativePixmap> native_pixmap_;
DISALLOW_COPY_AND_ASSIGN(GLImageGLXNativePixmap);
};
} // namespace gl
#endif // UI_GL_GL_IMAGE_GLX_NATIVE_PIXMAP_H_

@ -36,6 +36,12 @@ GLVisualPickerGLX* GLVisualPickerGLX::GetInstance() {
return base::Singleton<GLVisualPickerGLX>::get();
}
GLXFBConfig GLVisualPickerGLX::GetFbConfigForFormat(
gfx::BufferFormat format) const {
auto it = config_map_.find(format);
return it == config_map_.end() ? nullptr : it->second;
}
XVisualInfo GLVisualPickerGLX::PickBestGlVisual(
const std::vector<XVisualInfo>& visuals,
bool want_alpha) const {
@ -151,6 +157,75 @@ XVisualInfo GLVisualPickerGLX::PickBestRgbaVisual(
return PickBestGlVisual(filtered_visuals, true);
}
void GLVisualPickerGLX::FillConfigMap() {
if (!GLSurfaceGLX::HasGLXExtension("GLX_EXT_texture_from_pixmap"))
return;
std::vector<int> config_attribs{
// Ensure the config is compatible with pixmap drawing.
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
// Ensure we can bind to GL_TEXTURE_2D.
GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
// Ensure we don't get a color-indexed context.
GLX_RED_SIZE, 5, GLX_GREEN_SIZE, 6, GLX_BLUE_SIZE, 5,
// No double-buffering.
GLX_DOUBLEBUFFER, GL_FALSE,
// Prefer true-color over direct-color.
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR};
if (has_glx_visual_rating_) {
// No caveats.
config_attribs.push_back(GLX_CONFIG_CAVEAT);
config_attribs.push_back(GLX_NONE);
}
config_attribs.push_back(0);
int num_elements = 0;
gfx::XScopedPtr<GLXFBConfig> configs(
glXChooseFBConfig(display_, DefaultScreen(gfx::GetXDisplay()),
config_attribs.data(), &num_elements));
if (!configs.get()) {
DVLOG(0) << "glXChooseFBConfig failed.";
return;
}
if (!num_elements) {
DVLOG(0) << "glXChooseFBConfig returned 0 elements.";
return;
}
// Iterate from back to front since "preferred" FB configs appear earlier.
for (int i = num_elements; i-- > 0;) {
GLXFBConfig config = configs.get()[i];
// No antialiasing needed.
if (has_glx_multisample_) {
int msaa = 0;
glXGetFBConfigAttrib(display_, config, GLX_SAMPLES, &msaa);
if (msaa)
continue;
}
int r = 0, g = 0, b = 0, a = 0, depth = 0;
// No depth buffer needed.
glXGetFBConfigAttrib(display_, config, GLX_DEPTH_SIZE, &depth);
if (depth)
continue;
glXGetFBConfigAttrib(display_, config, GLX_RED_SIZE, &r);
glXGetFBConfigAttrib(display_, config, GLX_GREEN_SIZE, &g);
glXGetFBConfigAttrib(display_, config, GLX_BLUE_SIZE, &b);
glXGetFBConfigAttrib(display_, config, GLX_ALPHA_SIZE, &a);
if (r == 5 && g == 6 && b == 5 && a == 0)
config_map_[gfx::BufferFormat::BGR_565] = config;
else if (r == 8 && g == 8 && b == 8 && a == 0)
config_map_[gfx::BufferFormat::BGRX_8888] = config;
else if (r == 10 && g == 10 && b == 10 && a == 0)
config_map_[gfx::BufferFormat::BGRX_1010102] = config;
else if (r == 8 && g == 8 && b == 8 && a == 8)
config_map_[gfx::BufferFormat::BGRA_8888] = config;
}
}
GLVisualPickerGLX::GLVisualPickerGLX() : display_(gfx::GetXDisplay()) {
has_glx_visual_rating_ =
GLSurfaceGLX::HasGLXExtension("GLX_EXT_visual_rating");
@ -169,6 +244,8 @@ GLVisualPickerGLX::GLVisualPickerGLX() : display_(gfx::GetXDisplay()) {
system_visual_ = PickBestSystemVisual(visuals);
rgba_visual_ = PickBestRgbaVisual(visuals);
FillConfigMap();
}
GLVisualPickerGLX::~GLVisualPickerGLX() = default;

@ -7,7 +7,9 @@
#include <vector>
#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_types.h"
#include "ui/gl/gl_export.h"
@ -30,9 +32,11 @@ class GL_EXPORT GLVisualPickerGLX {
~GLVisualPickerGLX();
const XVisualInfo& system_visual() { return system_visual_; }
const XVisualInfo& system_visual() const { return system_visual_; }
const XVisualInfo& rgba_visual() { return rgba_visual_; }
const XVisualInfo& rgba_visual() const { return rgba_visual_; }
GLXFBConfig GetFbConfigForFormat(gfx::BufferFormat format) const;
private:
friend struct base::DefaultSingletonTraits<GLVisualPickerGLX>;
@ -45,6 +49,8 @@ class GL_EXPORT GLVisualPickerGLX {
XVisualInfo PickBestRgbaVisual(const std::vector<XVisualInfo>& visuals) const;
void FillConfigMap();
XDisplay* display_;
bool has_glx_visual_rating_;
@ -53,6 +59,8 @@ class GL_EXPORT GLVisualPickerGLX {
XVisualInfo system_visual_;
XVisualInfo rgba_visual_;
base::flat_map<gfx::BufferFormat, GLXFBConfig> config_map_;
GLVisualPickerGLX();
DISALLOW_COPY_AND_ASSIGN(GLVisualPickerGLX);