Drop support for OpenGL denylist on X11

...which appears to have become even less relevant with
db89f53c31 "remove OpenGL VCL backend code".  And
the vcl/unx/glxtest.cxx machinery that it is based on is (a) known to cause
issues like <https://gitlab.freedesktop.org/mesa/mesa/-/issues/3957>
"LibreOffice's OpenGL version detection code hangs when running inside a flatpak
container with a different mesa version", and (b) is one of the two reasons why
an soffice that uses Wayland nevertheless also requires Xwayland during startup
(the other reason being oosplash).  So getting rid of the glxtest machinery is
beneficial.

The remaining two potential uses of OpenGL on X11/Wayland are the obscure
css.rendering.SpriteCanvas.OGL service implementation (about which
db89f53c31 states that "it seems has never been
finished or enabled (or so it most probably should be dumped too)") and some
slideshow transitions.  About the latter, Caolán stated on IRC:  "I think we
grew this set of stuff to check for dodgy opengl primarily for the case where
vcl used opengl for ordinary UI optimizations; but I think that use is gone now
so I wonder does it make sense to just drop all of that entirely; for just slide
transitions we apparently survived fine without the denylist for ages".  (And in
any case there is still the WatchdogThread support with OpenGLZone::hardDisable
in VCLExceptionSignal_impl, vcl/source/app/svmain.cxx, should any OpenGL code
run into problems.)

(The removal of gb_LinkTarget_use_glxtest from gb_LinkTarget_use_vclmain, which
indirectly brought in gb_LinkTarget_use_libraries,*,vcl, revealed that an
explicit use of vcl was missing from various Executables etc., which thus had to
be added now.)

Change-Id: Ifa5220fd09910a4459ca546d9655e479a2e38f1e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131943
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
This commit is contained in:
Stephan Bergmann 2022-03-22 09:54:05 +01:00
parent 6b147d3369
commit 8a734ba928
27 changed files with 12 additions and 863 deletions

View file

@ -31,6 +31,7 @@ $(eval $(call gb_Executable_use_libraries,canvasdemo,\
tl \
sal \
salhelper \
vcl \
))
$(eval $(call gb_Executable_add_exception_objects,canvasdemo,\

View file

@ -169,8 +169,6 @@ bool ReservedId::VisitNamedDecl(NamedDecl const * decl) {
// vcl/source/window/cairo_cairo.cxx -> include/vcl/sysdata.hxx
&& s != "__CxxDetectRethrow"
// bridges/source/cpp_uno/msvc_win32_x86-64/mscx.hxx
&& s != "__GLXcontextRec" // vcl/unx/glxtest.cxx
&& s != "__GLXFBConfigRec" // vcl/unx/glxtest.cxx
&& s != "__PK11_GetKeyData"
// xmlsecurity/source/xmlsec/nss/nssrenam.h
&& s != "__current_exception" // bridges/inc/except.hxx, Windows

View file

@ -47,10 +47,9 @@ $(eval $(call gb_CppunitTest_use_libraries,desktop_app, \
tl \
ucbhelper \
utl \
vcl \
))
$(eval $(call gb_CppunitTest_use_glxtest,desktop_app,-lm))
ifeq ($(OS),WNT)
$(eval $(call gb_CppunitTest_use_static_libraries,desktop_app,\
$(if $(ENABLE_ONLINE_UPDATE_MAR),\

View file

@ -73,10 +73,9 @@ $(eval $(call gb_Library_use_libraries,sofficeapp,\
tl \
ucbhelper \
utl \
vcl \
))
$(eval $(call gb_Library_use_glxtest,sofficeapp,-lm))
ifeq ($(OS),WNT)
$(eval $(call gb_Library_use_static_libraries,sofficeapp,\
$(if $(ENABLE_ONLINE_UPDATE_MAR),\

View file

@ -105,7 +105,6 @@
#endif
#include <rtl/bootstrap.hxx>
#include <vcl/test/GraphicsRenderTests.hxx>
#include <vcl/glxtestprocess.hxx>
#include <vcl/help.hxx>
#include <vcl/weld.hxx>
#include <vcl/settings.hxx>
@ -1574,9 +1573,6 @@ int Desktop::Main()
//Running the VCL graphics rendering tests
runGraphicsRenderTests();
// Reap the process started by fire_glxtest_process().
reap_glxtest_process();
// Post user event to startup first application component window
// We have to send this OpenClients message short before execute() to
// minimize the risk that this message overtakes type detection construction!!

View file

@ -33,7 +33,6 @@
#include <sal/log.hxx>
#include <sal/main.h>
#include <tools/extendapplicationenvironment.hxx>
#include <vcl/glxtestprocess.hxx>
#include <vcl/svmain.hxx>
#if HAVE_FEATURE_BREAKPAD
@ -59,9 +58,6 @@ extern "C" int DESKTOP_DLLPUBLIC soffice_main()
CrashReporter::installExceptionHandler();
#endif
bool bSuccess = fire_glxtest_process();
SAL_WARN_IF(!bSuccess, "desktop.opengl", "problems with glxtest");
#if defined ANDROID
try {
rtl::Bootstrap::setIniFilename("file:///assets/program/lofficerc");

View file

@ -171,7 +171,6 @@ certain functionality.
@li @c desktop.lib
@li @c desktop.migration
@li @c desktop.offacc
@li @c desktop.opengl
@li @c desktop.splash
@li @c desktop.test
@li @c desktop.updater

View file

@ -1,34 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <sal/config.h>
#include <config_features.h>
#if defined(UNX) && !defined MACOSX && !defined IOS && !defined ANDROID && HAVE_FEATURE_UI \
&& HAVE_FEATURE_OPENGL
/* Run test for OpenGL support in own process to avoid crash with broken
* OpenGL drivers. Start process as early as possible.
* The process will be reaped late in Desktop::Main (desktop/source/app/app.cxx).
*/
bool fire_glxtest_process();
void reap_glxtest_process();
#else
inline bool fire_glxtest_process() { return true; }
inline void reap_glxtest_process() {}
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

View file

@ -14382,7 +14382,6 @@ vcl/inc/jobdata.hxx
vcl/inc/jobset.h
vcl/inc/listbox.hxx
vcl/inc/opengl/win/WinDeviceInfo.hxx
vcl/inc/opengl/x11/X11DeviceInfo.hxx
vcl/inc/osx/a11yfactory.h
vcl/inc/osx/a11yfocustracker.hxx
vcl/inc/osx/a11ywrapper.h
@ -14936,7 +14935,6 @@ vcl/source/opengl/OpenGLContext.cxx
vcl/source/opengl/OpenGLHelper.cxx
vcl/source/opengl/win/WinDeviceInfo.cxx
vcl/source/opengl/win/context.cxx
vcl/source/opengl/x11/X11DeviceInfo.cxx
vcl/source/opengl/x11/context.cxx
vcl/source/outdev/background.cxx
vcl/source/outdev/bitmap.cxx
@ -15123,7 +15121,6 @@ vcl/unx/generic/printer/printerinfomanager.cxx
vcl/unx/generic/window/salframe.cxx
vcl/unx/generic/window/salobj.cxx
vcl/unx/generic/window/screensaverinhibitor.cxx
vcl/unx/glxtest.cxx
vcl/unx/gtk3/a11y/atklistener.hxx
vcl/unx/gtk3/a11y/atkwrapper.hxx
vcl/unx/gtk3/a11y/atkaction.cxx

View file

@ -489,7 +489,6 @@ gb_CppunitTest_set_external_code = $(call gb_CppunitTest__forward_to_Linktarget,
gb_CppunitTest_set_generated_cxx_suffix = $(call gb_CppunitTest__forward_to_Linktarget,$(0),$(1),$(2),$(3))
gb_CppunitTest_use_clang = $(call gb_CppunitTest__forward_to_Linktarget,$(0),$(1),$(2),$(3))
gb_CppunitTest_set_clang_precompiled_header = $(call gb_CppunitTest__forward_to_Linktarget,$(0),$(1),$(2),$(3))
gb_CppunitTest_use_glxtest = $(call gb_CppunitTest__forward_to_Linktarget,$(0),$(1),$(2),$(3))
gb_CppunitTest_use_vclmain = $(call gb_CppunitTest__forward_to_Linktarget,$(0),$(1),$(2),$(3))
gb_CppunitTest_add_prejs = $(call gb_CppunitTest__forward_to_Linktarget,$(0),$(1),$(2),$(3))

View file

@ -157,7 +157,6 @@ gb_Executable_set_external_code = $(call gb_Executable__forward_to_Linktarget,$(
gb_Executable_set_generated_cxx_suffix = $(call gb_Executable__forward_to_Linktarget,$(0),$(1),$(2),$(3))
gb_Executable_use_clang = $(call gb_Executable__forward_to_Linktarget,$(0),$(1),$(2),$(3))
gb_Executable_set_clang_precompiled_header = $(call gb_Executable__forward_to_Linktarget,$(0),$(1),$(2),$(3))
gb_Executable_use_glxtest = $(call gb_Executable__forward_to_Linktarget,$(0),$(1),$(2),$(3))
gb_Executable_use_vclmain = $(call gb_Executable__forward_to_Linktarget,$(0),$(1),$(2),$(3))
gb_Executable_add_prejs = $(call gb_Executable__forward_to_Linktarget,$(0),$(1),$(2),$(3))

View file

@ -290,7 +290,6 @@ gb_Library_set_external_code = $(call gb_Library__forward_to_Linktarget,$(0),$(1
gb_Library_set_generated_cxx_suffix = $(call gb_Library__forward_to_Linktarget,$(0),$(1),$(2),$(3))
gb_Library_use_clang = $(call gb_Library__forward_to_Linktarget,$(0),$(1),$(2),$(3))
gb_Library_set_clang_precompiled_header = $(call gb_Library__forward_to_Linktarget,$(0),$(1),$(2),$(3))
gb_Library_use_glxtest = $(call gb_Library__forward_to_Linktarget,$(0),$(1),$(2),$(3))
gb_Library_use_vclmain = $(call gb_Library__forward_to_Linktarget,$(0),$(1),$(2),$(3))
gb_Library_set_is_ure_library_or_dependency = $(call gb_Library__forward_to_Linktarget,$(0),$(1),$(2),$(3))

View file

@ -2206,26 +2206,8 @@ $(call gb_LinkTarget_get_target,$(1)) : T_USE_LD := $(or $(CLANG_USE_LD),$(USE_L
$(call gb_LinkTarget_get_target,$(1)) : T_LTOFLAGS := $(or $(gb_CLANG_LTOFLAGS),$(gb_LTOFLAGS))
endef
# call gb_LinkTarget_use_glxtest,linktarget,add_libs
define gb_LinkTarget_use_glxtest
$(call gb_LinkTarget_use_libraries,$(1),vcl,,$(4))
ifeq (,$(DISABLE_DYNLOADING))
$(call gb_LinkTarget_add_libs,$(1),$(UNIX_DLAPI_LIBS))
endif
ifeq (,$(DISABLE_GUI))
ifeq ($(USING_X11),TRUE)
$(call gb_LinkTarget_add_libs,$(1),-lX11 $(2))
$(call gb_LinkTarget_use_static_libraries,$(1),glxtest)
endif
endif
endef # gb_LinkTarget_use_glxtest
# call gb_LinkTarget_use_vclmain,linktarget,add_libs
# call gb_LinkTarget_use_vclmain,linktarget
define gb_LinkTarget_use_vclmain
$(call gb_LinkTarget_use_glxtest,$(1),$(2))
$(call gb_LinkTarget_use_static_libraries,$(1),vclmain)
endef # gb_LinkTarget_use_vclmain

View file

@ -45,6 +45,7 @@ $(eval $(call gb_Executable_use_libraries,gengal,\
cppuhelper \
utl \
svxcore \
vcl \
))
$(eval $(call gb_Executable_use_vclmain,gengal))

View file

@ -37,6 +37,7 @@ $(eval $(call gb_Executable_use_libraries,icontest,\
sal \
tl \
ucbhelper \
vcl \
))
$(eval $(call gb_Executable_use_vclmain,icontest))

View file

@ -31,6 +31,7 @@ $(eval $(call gb_Executable_use_libraries,mtfdemo,\
drawinglayer \
emfio \
i18nlangtag \
vcl \
))
$(eval $(call gb_Executable_use_vclmain,mtfdemo))

View file

@ -40,6 +40,7 @@ $(eval $(call gb_Executable_use_libraries,vcldemo,\
salhelper \
fwk \
i18nlangtag \
vcl \
))
$(eval $(call gb_Executable_use_vclmain,vcldemo))

View file

@ -28,9 +28,10 @@ $(eval $(call gb_Executable_use_libraries,visualbackendtest,\
tl \
sal \
salhelper \
vcl \
))
$(eval $(call gb_Executable_use_vclmain,visualbackendtest,-lm))
$(eval $(call gb_Executable_use_vclmain,visualbackendtest))
$(eval $(call gb_Executable_add_exception_objects,visualbackendtest,\
vcl/backendtest/VisualBackendTest \

View file

@ -584,15 +584,6 @@ $(eval $(call gb_Library_add_libs,vcl,\
-lX11 \
-lXext \
))
ifneq (,$(filter LINUX %BSD SOLARIS,$(OS)))
$(eval $(call gb_Library_use_static_libraries,vcl,\
glxtest \
))
$(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/source/opengl/x11/X11DeviceInfo \
))
endif
endif # USING_X11

View file

@ -70,7 +70,6 @@ ifeq ($(USING_X11),TRUE)
$(eval $(call gb_Module_add_targets,vcl,\
$(if $(ENABLE_GEN),Library_vclplug_gen) \
Library_desktop_detector \
StaticLibrary_glxtest \
Package_fontunxppds \
Package_fontunxpsprint \
))

View file

@ -1,41 +0,0 @@
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This file incorporates work covered by the following license notice:
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed
# with this work for additional information regarding copyright
# ownership. The ASF licenses this file to you under the Apache
# License, Version 2.0 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.apache.org/licenses/LICENSE-2.0 .
#
$(eval $(call gb_StaticLibrary_StaticLibrary,glxtest))
$(eval $(call gb_StaticLibrary_set_include,glxtest,\
$$(INCLUDE) \
-I$(SRCDIR)/vcl/inc \
))
$(eval $(call gb_StaticLibrary_use_api,glxtest,\
offapi \
udkapi \
))
$(eval $(call gb_StaticLibrary_add_libs,glxtest,\
-lm $(UNIX_DLAPI_LIBS) \
-lX11 \
))
$(eval $(call gb_StaticLibrary_add_exception_objects,glxtest,\
vcl/unx/glxtest \
))
# vim: set noet sw=4 ts=4:

View file

@ -1,48 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef INCLUDED_VCL_INC_OPENGL_X11_X11DEVICEINFO_HXX
#define INCLUDED_VCL_INC_OPENGL_X11_X11DEVICEINFO_HXX
#include <rtl/string.hxx>
class X11OpenGLDeviceInfo final
{
private:
bool mbIsMesa;
bool mbIsNVIDIA;
bool mbIsFGLRX;
bool mbIsNouveau;
bool mbIsIntel;
bool mbIsOldSwrast;
bool mbIsLlvmpipe;
OString maVendor;
OString maRenderer;
OString maVersion;
OString maOS;
OString maOSRelease;
size_t mnGLMajorVersion;
size_t mnMajorVersion;
size_t mnMinorVersion;
size_t mnRevisionVersion;
void GetData();
public:
X11OpenGLDeviceInfo();
bool isDeviceBlocked();
};
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View file

@ -1,21 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef INCLUDED_VCL_INC_OPENGL_X11_GLXTEST_HXX
#define INCLUDED_VCL_INC_OPENGL_X11_GLXTEST_HXX
#include <vcl/dllapi.h>
VCL_DLLPUBLIC int* getGlxPipe();
VCL_DLLPUBLIC pid_t* getGlxPid();
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View file

@ -37,13 +37,10 @@
#include <bitmap/BitmapWriteAccess.hxx>
#include <watchdog.hxx>
#include <vcl/skia/SkiaHelper.hxx>
#include <vcl/glxtestprocess.hxx>
#include <salinst.hxx>
#include <svdata.hxx>
#if USING_X11
#include <opengl/x11/X11DeviceInfo.hxx>
#elif defined (_WIN32)
#if defined (_WIN32)
#include <opengl/win/WinDeviceInfo.hxx>
#endif
@ -756,11 +753,7 @@ bool OpenGLHelper::isDeviceDenylisted()
{
OpenGLZone aZone;
#if USING_X11
X11OpenGLDeviceInfo aInfo;
bDenylisted = aInfo.isDeviceBlocked();
SAL_INFO("vcl.opengl", "denylisted: " << bDenylisted);
#elif defined( _WIN32 )
#if defined( _WIN32 )
WinOpenGLDeviceInfo aInfo;
bDenylisted = aInfo.isDeviceBlocked();

View file

@ -1,363 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <opengl/x11/X11DeviceInfo.hxx>
#include <opengl/x11/glxtest.hxx>
#include <config_features.h>
#include <rtl/ustring.hxx>
#include <sal/log.hxx>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <sys/utsname.h>
#include <desktop/crashreport.hxx>
namespace glx {
static int glxtest_pipe = 0;
static pid_t glxtest_pid = 0;
}
pid_t* getGlxPid()
{
return &glx::glxtest_pid;
}
int* getGlxPipe()
{
return &glx::glxtest_pipe;
}
namespace {
const char*
strspnp_wrapper(const char* aDelims, const char* aStr)
{
const char* d;
do
{
for (d = aDelims; *d != '\0'; ++d)
{
if (*aStr == *d)
{
++aStr;
break;
}
}
} while (*d);
return aStr;
}
char* strtok_wrapper(const char* aDelims, char** aStr)
{
if (!*aStr)
{
return nullptr;
}
char* ret = const_cast<char*>(strspnp_wrapper(aDelims, *aStr));
if (!*ret)
{
*aStr = ret;
return nullptr;
}
char* i = ret;
do
{
for (const char* d = aDelims; *d != '\0'; ++d)
{
if (*i == *d) {
*i = '\0';
*aStr = ++i;
return ret;
}
}
++i;
} while (*i);
*aStr = nullptr;
return ret;
}
uint64_t version(uint32_t major, uint32_t minor, uint32_t revision = 0)
{
return (uint64_t(major) << 32) + (uint64_t(minor) << 16) + uint64_t(revision);
}
}
X11OpenGLDeviceInfo::X11OpenGLDeviceInfo():
mbIsMesa(false),
mbIsNVIDIA(false),
mbIsFGLRX(false),
mbIsNouveau(false),
mbIsIntel(false),
mbIsOldSwrast(false),
mbIsLlvmpipe(false),
mnGLMajorVersion(0),
mnMajorVersion(0),
mnMinorVersion(0),
mnRevisionVersion(0)
{
GetData();
}
void X11OpenGLDeviceInfo::GetData()
{
if (!glx::glxtest_pipe)
return;
// to understand this function, see bug moz#639842. We retrieve the OpenGL driver information in a
// separate process to protect against bad drivers.
enum { buf_size = 1024 };
char buf[buf_size];
ssize_t bytesread = read(glx::glxtest_pipe,
&buf,
buf_size-1); // -1 because we'll append a zero
close(glx::glxtest_pipe);
glx::glxtest_pipe = 0;
// bytesread < 0 would mean that the above read() call failed.
// This should never happen. If it did, the outcome would be to denylist anyway.
if (bytesread < 0)
bytesread = 0;
// let buf be a zero-terminated string
buf[bytesread] = 0;
// Wait for the glxtest process to finish. This serves 2 purposes:
// * avoid having a zombie glxtest process laying around
// * get the glxtest process status info.
int glxtest_status = 0;
bool wait_for_glxtest_process = true;
bool waiting_for_glxtest_process_failed = false;
int waitpid_errno = 0;
while(wait_for_glxtest_process)
{
wait_for_glxtest_process = false;
if (waitpid(glx::glxtest_pid, &glxtest_status, 0) == -1)
{
waitpid_errno = errno;
if (waitpid_errno == EINTR)
{
wait_for_glxtest_process = true;
}
else
{
// Bug moz#718629
// ECHILD happens when the glxtest process got reaped got reaped after a PR_CreateProcess
// as per bug moz#227246. This shouldn't matter, as we still seem to get the data
// from the pipe, and if we didn't, the outcome would be to denylist anyway.
waiting_for_glxtest_process_failed = (waitpid_errno != ECHILD);
}
}
}
bool exited_with_error_code = !waiting_for_glxtest_process_failed &&
WIFEXITED(glxtest_status) &&
WEXITSTATUS(glxtest_status) != EXIT_SUCCESS;
bool received_signal = !waiting_for_glxtest_process_failed &&
WIFSIGNALED(glxtest_status);
bool error = waiting_for_glxtest_process_failed || exited_with_error_code || received_signal;
OString textureFromPixmap;
OString *stringToFill = nullptr;
char *bufptr = buf;
if (!error)
{
while(true)
{
char *line = strtok_wrapper("\n", &bufptr);
if (!line)
break;
if (stringToFill) {
*stringToFill = OString(line);
stringToFill = nullptr;
}
else if(!strcmp(line, "VENDOR"))
stringToFill = &maVendor;
else if(!strcmp(line, "RENDERER"))
stringToFill = &maRenderer;
else if(!strcmp(line, "VERSION"))
stringToFill = &maVersion;
else if(!strcmp(line, "TFP"))
stringToFill = &textureFromPixmap;
}
}
// only useful for Linux kernel version check for FGLRX driver.
// assumes X client == X server, which is sad.
struct utsname unameobj;
if (!uname(&unameobj))
{
maOS = OString(unameobj.sysname);
maOSRelease = OString(unameobj.release);
}
// determine the major OpenGL version. That's the first integer in the version string.
mnGLMajorVersion = strtol(maVersion.getStr(), nullptr, 10);
// determine driver type (vendor) and where in the version string
// the actual driver version numbers should be expected to be found (whereToReadVersionNumbers)
const char *whereToReadVersionNumbers = nullptr;
const char *Mesa_in_version_string = strstr(maVersion.getStr(), "Mesa");
if (Mesa_in_version_string)
{
mbIsMesa = true;
// with Mesa, the version string contains "Mesa major.minor" and that's all the version information we get:
// there is no actual driver version info.
whereToReadVersionNumbers = Mesa_in_version_string + strlen("Mesa");
if (strcasestr(maVendor.getStr(), "nouveau"))
mbIsNouveau = true;
if (strcasestr(maRenderer.getStr(), "intel")) // yes, intel is in the renderer string
mbIsIntel = true;
if (strcasestr(maRenderer.getStr(), "llvmpipe"))
mbIsLlvmpipe = true;
if (strcasestr(maRenderer.getStr(), "software rasterizer"))
mbIsOldSwrast = true;
}
else if (strstr(maVendor.getStr(), "NVIDIA Corporation"))
{
mbIsNVIDIA = true;
// with the NVIDIA driver, the version string contains "NVIDIA major.minor"
// note that here the vendor and version strings behave differently, that's why we don't put this above
// alongside Mesa_in_version_string.
const char *NVIDIA_in_version_string = strstr(maVersion.getStr(), "NVIDIA");
if (NVIDIA_in_version_string)
whereToReadVersionNumbers = NVIDIA_in_version_string + strlen("NVIDIA");
}
else if (strstr(maVendor.getStr(), "ATI Technologies Inc"))
{
mbIsFGLRX = true;
// with the FGLRX driver, the version string only gives an OpenGL version: so let's return that.
// that can at least give a rough idea of how old the driver is.
whereToReadVersionNumbers = maVersion.getStr();
}
// read major.minor version numbers of the driver (not to be confused with the OpenGL version)
if (!whereToReadVersionNumbers)
return;
// copy into writable buffer, for tokenization
strncpy(buf, whereToReadVersionNumbers, buf_size-1);
buf[buf_size-1] = 0;
bufptr = buf;
// now try to read major.minor version numbers. In case of failure, gracefully exit: these numbers have
// been initialized as 0 anyways
char *token = strtok_wrapper(".", &bufptr);
if (token)
{
mnMajorVersion = strtol(token, nullptr, 10);
token = strtok_wrapper(".", &bufptr);
if (token)
{
mnMinorVersion = strtol(token, nullptr, 10);
token = strtok_wrapper(".", &bufptr);
if (token)
mnRevisionVersion = strtol(token, nullptr, 10);
}
}
}
bool X11OpenGLDeviceInfo::isDeviceBlocked()
{
// don't even try to use OpenGL 1.x
if (mnGLMajorVersion == 1)
return true;
CrashReporter::addKeyValue("AdapterVendorId", OStringToOUString(maVendor, RTL_TEXTENCODING_UTF8), CrashReporter::AddItem);
CrashReporter::addKeyValue("AdapterDeviceId", OStringToOUString(maRenderer, RTL_TEXTENCODING_UTF8), CrashReporter::Write);
SAL_INFO("vcl.opengl", "Vendor: " << maVendor);
SAL_INFO("vcl.opengl", "Renderer: " << maRenderer);
SAL_INFO("vcl.opengl", "Version: " << maVersion);
SAL_INFO("vcl.opengl", "OS: " << maOS);
SAL_INFO("vcl.opengl", "OSRelease: " << maOSRelease);
if (mbIsMesa)
{
if (mbIsNouveau && version(mnMajorVersion, mnMinorVersion) < version(8,0))
{
SAL_WARN("vcl.opengl", "blocked driver version: old nouveau driver (requires mesa 8.0+)");
return true;
}
else if (version(mnMajorVersion, mnMinorVersion, mnRevisionVersion) < version(7,10,3))
{
SAL_WARN("vcl.opengl", "blocked driver version: requires at least mesa 7.10.3");
return true;
}
else if (mbIsIntel && version(mnMajorVersion, mnMinorVersion, mnRevisionVersion) == version(9,0,2))
{
SAL_WARN("vcl.opengl", "blocked driver version: my broken intel driver Mesa 9.0.2");
return true;
}
else if (mbIsOldSwrast)
{
SAL_WARN("vcl.opengl", "blocked driver version: software rasterizer");
return true;
}
else if (mbIsLlvmpipe && version(mnMajorVersion, mnMinorVersion) < version(9, 1))
{
// bug moz#791905, Mesa bug 57733, fixed in Mesa 9.1 according to
// https://bugs.freedesktop.org/show_bug.cgi?id=57733#c3
SAL_WARN("vcl.opengl", "blocked driver version: fdo#57733");
return true;
}
}
else if (mbIsNVIDIA)
{
if (version(mnMajorVersion, mnMinorVersion, mnRevisionVersion) < version(257,21))
{
SAL_WARN("vcl.opengl", "blocked driver version: nvidia requires at least 257.21");
return true;
}
}
else if (mbIsFGLRX)
{
// FGLRX does not report a driver version number, so we have the OpenGL version instead.
// by requiring OpenGL 3, we effectively require recent drivers.
if (version(mnMajorVersion, mnMinorVersion, mnRevisionVersion) < version(3, 0))
{
SAL_WARN("vcl.opengl", "blocked driver version: require at least OpenGL 3 for fglrx");
return true;
}
// Bug moz#724640: FGLRX + Linux 2.6.32 is a crashy combo
bool unknownOS = maOS.isEmpty() || maOSRelease.isEmpty();
bool badOS = maOS.indexOf("Linux") != -1 &&
maOSRelease.indexOf("2.6.32") != -1;
if (unknownOS || badOS)
{
SAL_WARN("vcl.opengl", "blocked OS version with fglrx");
return true;
}
}
else
{
// like on windows, let's block unknown vendors. Think of virtual machines.
// Also, this case is hit whenever the GLXtest probe failed to get driver info or crashed.
SAL_WARN("vcl.opengl", "unknown vendor => blocked");
return true;
}
return false;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View file

@ -22,13 +22,11 @@
#include <sal/main.h>
#include <tools/extendapplicationenvironment.hxx>
#include <vcl/glxtestprocess.hxx>
#include <vcl/vclmain.hxx>
#include <vcl/svmain.hxx>
SAL_IMPLEMENT_MAIN()
{
fire_glxtest_process();
tools::extendApplicationEnvironment();
vclmain::createApplication();
return SVMain();

View file

@ -1,294 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//////////////////////////////////////////////////////////////////////////////
//
// Explanation: See bug 639842. Safely getting GL driver info on X11 is hard, because the only way to do
// that is to create a GL context and call glGetString(), but with bad drivers,
// just creating a GL context may crash.
//
// This file implements the idea to do that in a separate process.
//
// The only non-static function here is fire_glxtest_process(). It creates a pipe, publishes its 'read' end as the
// mozilla::widget::glxtest_pipe global variable, forks, and runs that GLX probe in the child process,
// which runs the glxtest() static function. This creates a X connection, a GLX context, calls glGetString, and writes that
// to the 'write' end of the pipe.
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <stdint.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <opengl/x11/glxtest.hxx>
#ifdef __SUNPRO_CC
#include <stdio.h>
#endif
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <sal/log.hxx>
#include <vcl/glxtestprocess.hxx>
// stuff from glx.h
typedef struct __GLXcontextRec *GLXContext;
typedef XID GLXPixmap;
typedef XID GLXDrawable;
/* GLX 1.3 and later */
typedef struct __GLXFBConfigRec *GLXFBConfig;
#define GLX_RGBA 4
#define GLX_RED_SIZE 8
#define GLX_GREEN_SIZE 9
#define GLX_BLUE_SIZE 10
// stuff from gl.h
typedef uint8_t GLubyte;
typedef uint32_t GLenum;
#define GL_VENDOR 0x1F00
#define GL_RENDERER 0x1F01
#define GL_VERSION 0x1F02
// the write end of the pipe, which we're going to write to
static int write_end_of_the_pipe = -1;
// C++ standard collides with C standard in that it doesn't allow casting void* to function pointer types.
// So the work-around is to convert first to size_t.
// http://www.trilithium.com/johan/2004/12/problem-with-dlsym/
template<typename func_ptr_type>
static func_ptr_type cast(void *ptr)
{
return reinterpret_cast<func_ptr_type>(
reinterpret_cast<size_t>(ptr)
);
}
static void fatal_error(const char *str)
{
int length = strlen(str);
if (write(write_end_of_the_pipe, str, length) != length
|| write(write_end_of_the_pipe, "\n", 1) != 1)
{
/* Cannot write to pipe. Fall through to call _exit */
}
_exit(EXIT_FAILURE);
}
static int
x_error_handler(Display *, XErrorEvent *ev)
{
enum { bufsize = 1024 };
char buf[bufsize];
int length = snprintf(buf, bufsize,
"X error occurred in GLX probe, error_code=%d, request_code=%d, minor_code=%d\n",
ev->error_code,
ev->request_code,
ev->minor_code);
if (write(write_end_of_the_pipe, buf, length) != length)
{
/* Cannot write to pipe. Fall through to call _exit */
}
_exit(EXIT_FAILURE);
return 0;
}
static void glxtest()
{
signal(SIGPIPE, SIG_IGN);
// we want to redirect to /dev/null stdout, stderr, and while we're at it,
// any PR logging file descriptors. To that effect, we redirect all positive
// file descriptors up to what open() returns here. In particular, 1 is stdout and 2 is stderr.
int fd = open("/dev/null", O_WRONLY);
if (fd == -1)
fatal_error("could not redirect stdout+stderr");
for (int i = 1; i < fd; i++)
dup2(fd, i);
close(fd);
///// Open libGL and load needed symbols /////
#ifdef __OpenBSD__
#define LIBGL_FILENAME "libGL.so"
#else
#define LIBGL_FILENAME "libGL.so.1"
#endif
void *libgl = dlopen(LIBGL_FILENAME, RTLD_LAZY);
if (!libgl)
fatal_error("Unable to load " LIBGL_FILENAME);
typedef void* (* PFNGLXGETPROCADDRESS) (const char *);
PFNGLXGETPROCADDRESS glXGetProcAddress = cast<PFNGLXGETPROCADDRESS>(dlsym(libgl, "glXGetProcAddress"));
if (!glXGetProcAddress)
fatal_error("Unable to find glXGetProcAddress in " LIBGL_FILENAME);
typedef GLXFBConfig* (* PFNGLXQUERYEXTENSION) (Display *, int *, int *);
PFNGLXQUERYEXTENSION glXQueryExtension = cast<PFNGLXQUERYEXTENSION>(glXGetProcAddress("glXQueryExtension"));
typedef GLXFBConfig* (* PFNGLXQUERYVERSION) (Display *, int *, int *);
PFNGLXQUERYVERSION glXQueryVersion = cast<PFNGLXQUERYVERSION>(dlsym(libgl, "glXQueryVersion"));
typedef XVisualInfo* (* PFNGLXCHOOSEVISUAL) (Display *, int, int *);
PFNGLXCHOOSEVISUAL glXChooseVisual = cast<PFNGLXCHOOSEVISUAL>(glXGetProcAddress("glXChooseVisual"));
typedef GLXContext (* PFNGLXCREATECONTEXT) (Display *, XVisualInfo *, GLXContext, Bool);
PFNGLXCREATECONTEXT glXCreateContext = cast<PFNGLXCREATECONTEXT>(glXGetProcAddress("glXCreateContext"));
typedef Bool (* PFNGLXMAKECURRENT) (Display*, GLXDrawable, GLXContext);
PFNGLXMAKECURRENT glXMakeCurrent = cast<PFNGLXMAKECURRENT>(glXGetProcAddress("glXMakeCurrent"));
typedef void (* PFNGLXDESTROYCONTEXT) (Display*, GLXContext);
PFNGLXDESTROYCONTEXT glXDestroyContext = cast<PFNGLXDESTROYCONTEXT>(glXGetProcAddress("glXDestroyContext"));
typedef GLubyte* (* PFNGLGETSTRING) (GLenum);
PFNGLGETSTRING glGetString = cast<PFNGLGETSTRING>(glXGetProcAddress("glGetString"));
if (!glXQueryExtension ||
!glXQueryVersion ||
!glXChooseVisual ||
!glXCreateContext ||
!glXMakeCurrent ||
!glXDestroyContext ||
!glGetString)
{
fatal_error("glXGetProcAddress couldn't find required functions");
}
///// Open a connection to the X server /////
Display *dpy = XOpenDisplay(nullptr);
if (!dpy)
fatal_error("Unable to open a connection to the X server");
///// Check that the GLX extension is present /////
if (!glXQueryExtension(dpy, nullptr, nullptr))
fatal_error("GLX extension missing");
XSetErrorHandler(x_error_handler);
///// Get a visual /////
int attribs[] = {
GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
None };
XVisualInfo *vInfo = glXChooseVisual(dpy, DefaultScreen(dpy), attribs);
if (!vInfo)
fatal_error("No visuals found");
// using a X11 Window instead of a GLXPixmap does not crash
// fglrx in indirect rendering. bug 680644
Window window;
XSetWindowAttributes swa;
swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vInfo->screen),
vInfo->visual, AllocNone);
swa.border_pixel = 0;
window = XCreateWindow(dpy, RootWindow(dpy, vInfo->screen),
0, 0, 16, 16,
0, vInfo->depth, InputOutput, vInfo->visual,
CWBorderPixel | CWColormap, &swa);
///// Get a GL context and make it current //////
GLXContext context = glXCreateContext(dpy, vInfo, nullptr, True);
glXMakeCurrent(dpy, window, context);
///// Look for this symbol to determine texture_from_pixmap support /////
void* glXBindTexImageEXT = glXGetProcAddress("glXBindTexImageEXT");
///// Get GL vendor/renderer/versions strings /////
enum { bufsize = 1024 };
char buf[bufsize];
const GLubyte *vendorString = glGetString(GL_VENDOR);
const GLubyte *rendererString = glGetString(GL_RENDERER);
const GLubyte *versionString = glGetString(GL_VERSION);
if (!vendorString || !rendererString || !versionString)
fatal_error("glGetString returned null");
int length = snprintf(buf, bufsize,
"VENDOR\n%s\nRENDERER\n%s\nVERSION\n%s\nTFP\n%s\n",
vendorString,
rendererString,
versionString,
glXBindTexImageEXT ? "TRUE" : "FALSE");
if (length >= bufsize)
fatal_error("GL strings length too large for buffer size");
///// Clean up. Indeed, the parent process might fail to kill us (e.g. if it doesn't need to check GL info)
///// so we might be staying alive for longer than expected, so it's important to consume as little memory as
///// possible. Also we want to check that we're able to do that too without generating X errors.
glXMakeCurrent(dpy, None, nullptr); // must release the GL context before destroying it
glXDestroyContext(dpy, context);
XDestroyWindow(dpy, window);
XFreeColormap(dpy, swa.colormap);
XFree(vInfo);
#ifdef NS_FREE_PERMANENT_DATA // conditionally defined in nscore.h, don't forget to #include it above
XCloseDisplay(dpy);
#else
// This XSync call wanted to be instead:
// XCloseDisplay(dpy);
// but this can cause 1-minute stalls on certain setups using Nouveau, see bug 973192
XSync(dpy, False);
#endif
dlclose(libgl);
///// Finally write data to the pipe
if (write(write_end_of_the_pipe, buf, length) != length)
fatal_error("Could not write to pipe");
}
/** \returns true in the child glxtest process, false in the parent process */
bool fire_glxtest_process()
{
int pfd[2];
if (pipe(pfd) == -1) {
perror("pipe");
return false;
}
pid_t pid = fork();
if (pid < 0) {
perror("fork");
close(pfd[0]);
close(pfd[1]);
return false;
}
// The child exits early to avoid running the full shutdown sequence and avoid conflicting with threads
// we have already spawned (like the profiler).
if (pid == 0) {
close(pfd[0]);
write_end_of_the_pipe = pfd[1];
glxtest();
close(pfd[1]);
_exit(0);
}
close(pfd[1]);
int* glxtest_pipe = getGlxPipe();
*glxtest_pipe = pfd[0];
pid_t* glxtest_pid = getGlxPid();
*glxtest_pid = pid;
return true;
}
void reap_glxtest_process() {
pid_t * pid = getGlxPid();
if (*pid != 0) {
// Use WNOHANG, as it is probably better to have a (rather harmless) zombie child process
// hanging around for the duration of the calling process, than to potentially block the
// calling process here:
pid_t e = waitpid(*pid, nullptr, WNOHANG);
SAL_INFO_IF(
e <= 0, "vcl.opengl", "waiting for glxtest process " << *pid << " failed with " << e);
}
}