From 5a6bcfe5cc034e908c310f3405b62bd35f6a8793 Mon Sep 17 00:00:00 2001 From: dyen Date: Wed, 13 May 2015 17:09:33 -0700 Subject: [PATCH] Added switch to disable specified GL extensions. It is now possible to remove extensions from the GL_EXTENSIONS string by specifying "--disable-gl-extensions=extension1,extension2". R=sievers@chromium.org BUG=482067 Review URL: https://codereview.chromium.org/1110923003 Cr-Commit-Position: refs/heads/master@{#329752} --- build/all.gyp | 6 +- content/browser/gpu/gpu_process_host.cc | 1 + ui/gl/BUILD.gn | 1 + ui/gl/gl_api_unittest.cc | 153 ++++++++++++++++++++++++++++++++ ui/gl/gl_gl_api_implementation.cc | 72 ++++++++++++++- ui/gl/gl_gl_api_implementation.h | 19 +++- ui/gl/gl_switches.cc | 3 + ui/gl/gl_switches.h | 1 + ui/gl/gl_tests.gyp | 2 + 9 files changed, 254 insertions(+), 4 deletions(-) create mode 100644 ui/gl/gl_api_unittest.cc diff --git a/build/all.gyp b/build/all.gyp index 1866c2efdb51..48370974cad7 100644 --- a/build/all.gyp +++ b/build/all.gyp @@ -319,10 +319,14 @@ '../ui/base/ui_base_tests.gyp:ui_base_unittests', '../ui/display/display.gyp:display_unittests', '../ui/gfx/gfx_tests.gyp:gfx_unittests', - '../ui/gl/gl_tests.gyp:gl_unittests', '../url/url.gyp:url_unittests', ], 'conditions': [ + ['OS!="ios"', { + 'dependencies': [ + '../ui/gl/gl_tests.gyp:gl_unittests', + ], + }], ['OS!="ios" and OS!="mac"', { 'dependencies': [ '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests', diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index 52b09f2e6da3..2384a1b2cc24 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc @@ -77,6 +77,7 @@ static const char* const kSwitchNames[] = { switches::kDisableBreakpad, switches::kDisableGpuSandbox, switches::kDisableGpuWatchdog, + switches::kDisableGLExtensions, switches::kDisableLogging, switches::kDisableSeccompFilterSandbox, #if defined(ENABLE_WEBRTC) diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn index 76ed117d9024..2dc61403817b 100644 --- a/ui/gl/BUILD.gn +++ b/ui/gl/BUILD.gn @@ -280,6 +280,7 @@ source_set("gl_unittest_utils") { test("gl_unittests") { sources = [ + "gl_api_unittest.cc", "test/run_all_unittests.cc", ] diff --git a/ui/gl/gl_api_unittest.cc b/ui/gl/gl_api_unittest.cc new file mode 100644 index 000000000000..98025d118ac9 --- /dev/null +++ b/ui/gl/gl_api_unittest.cc @@ -0,0 +1,153 @@ +// Copyright 2015 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 "base/command_line.h" +#include "base/memory/scoped_ptr.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gl/gl_gl_api_implementation.h" +#include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_switches.h" + +namespace gfx { + +class GLApiTest : public testing::Test { + public: + void SetUp() override { + fake_extension_string_ = ""; + num_fake_extension_strings_ = 0; + fake_extension_strings_ = nullptr; + + driver_.reset(new DriverGL()); + api_.reset(new RealGLApi()); + + driver_->fn.glGetStringFn = &FakeGetString; + driver_->fn.glGetStringiFn = &FakeGetStringi; + driver_->fn.glGetIntegervFn = &FakeGetIntegervFn; + } + + void TearDown() override { + api_.reset(nullptr); + driver_.reset(nullptr); + + SetGLImplementation(kGLImplementationNone); + fake_extension_string_ = ""; + num_fake_extension_strings_ = 0; + fake_extension_strings_ = nullptr; + } + + void InitializeAPI(base::CommandLine* command_line) { + api_.reset(new RealGLApi()); + if (command_line) + api_->InitializeWithCommandLine(driver_.get(), command_line); + else + api_->Initialize(driver_.get()); + } + + void SetFakeExtensionString(const char* fake_string) { + SetGLImplementation(kGLImplementationDesktopGL); + fake_extension_string_ = fake_string; + } + + void SetFakeExtensionStrings(const char** fake_strings, uint32_t count) { + SetGLImplementation(kGLImplementationDesktopGLCoreProfile); + num_fake_extension_strings_ = count; + fake_extension_strings_ = fake_strings; + } + + static const GLubyte* GL_BINDING_CALL FakeGetString(GLenum name) { + return reinterpret_cast(fake_extension_string_); + } + + static void GL_BINDING_CALL FakeGetIntegervFn(GLenum pname, GLint* params) { + *params = num_fake_extension_strings_; + } + + static const GLubyte* GL_BINDING_CALL FakeGetStringi(GLenum name, + GLuint index) { + return (index < num_fake_extension_strings_) ? + reinterpret_cast(fake_extension_strings_[index]) : + nullptr; + } + + const char* GetExtensions() { + return reinterpret_cast(api_->glGetStringFn(GL_EXTENSIONS)); + } + + uint32_t GetNumExtensions() { + GLint num_extensions = 0; + api_->glGetIntegervFn(GL_NUM_EXTENSIONS, &num_extensions); + return static_cast(num_extensions); + } + + const char* GetExtensioni(uint32_t index) { + return reinterpret_cast(api_->glGetStringiFn(GL_EXTENSIONS, + index)); + } + + protected: + static const char* fake_extension_string_; + + static uint32_t num_fake_extension_strings_; + static const char** fake_extension_strings_; + + scoped_ptr driver_; + scoped_ptr api_; +}; + +const char* GLApiTest::fake_extension_string_ = ""; + +uint32_t GLApiTest::num_fake_extension_strings_ = 0; +const char** GLApiTest::fake_extension_strings_ = nullptr; + +TEST_F(GLApiTest, DisabledExtensionStringTest) { + static const char* kFakeExtensions = "GL_EXT_1 GL_EXT_2 GL_EXT_3 GL_EXT_4"; + static const char* kFakeDisabledExtensions = "GL_EXT_1,GL_EXT_2,GL_FAKE"; + static const char* kFilteredExtensions = "GL_EXT_3 GL_EXT_4"; + + SetFakeExtensionString(kFakeExtensions); + InitializeAPI(nullptr); + + EXPECT_STREQ(kFakeExtensions, GetExtensions()); + + base::CommandLine command_line(base::CommandLine::NO_PROGRAM); + command_line.AppendSwitchASCII(switches::kDisableGLExtensions, + kFakeDisabledExtensions); + InitializeAPI(&command_line); + + EXPECT_STREQ(kFilteredExtensions, GetExtensions()); +} + +TEST_F(GLApiTest, DisabledExtensionStringIndexTest) { + static const char* kFakeExtensions[] = { + "GL_EXT_1", + "GL_EXT_2", + "GL_EXT_3", + "GL_EXT_4" + }; + static const char* kFakeDisabledExtensions = "GL_EXT_1,GL_EXT_2,GL_FAKE"; + static const char* kFilteredExtensions[] = { + "GL_EXT_3", + "GL_EXT_4" + }; + + SetFakeExtensionStrings(kFakeExtensions, arraysize(kFakeExtensions)); + InitializeAPI(nullptr); + + EXPECT_EQ(arraysize(kFakeExtensions), GetNumExtensions()); + for (uint32_t i = 0; i < arraysize(kFakeExtensions); ++i) { + EXPECT_STREQ(kFakeExtensions[i], GetExtensioni(i)); + } + + base::CommandLine command_line(base::CommandLine::NO_PROGRAM); + command_line.AppendSwitchASCII(switches::kDisableGLExtensions, + kFakeDisabledExtensions); + InitializeAPI(&command_line); + + EXPECT_EQ(arraysize(kFilteredExtensions), GetNumExtensions()); + for (uint32_t i = 0; i < arraysize(kFilteredExtensions); ++i) { + EXPECT_STREQ(kFilteredExtensions[i], GetExtensioni(i)); + } +} + +} // namespace gpu diff --git a/ui/gl/gl_gl_api_implementation.cc b/ui/gl/gl_gl_api_implementation.cc index 6752a25ee5a8..3a7e2491e6cb 100644 --- a/ui/gl/gl_gl_api_implementation.cc +++ b/ui/gl/gl_gl_api_implementation.cc @@ -8,6 +8,7 @@ #include #include "base/command_line.h" +#include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_implementation.h" @@ -309,7 +310,7 @@ void InitializeStaticGLBindingsGL() { } GLApi* GetCurrentGLApi() { - return g_current_gl_context_tls->Get(); + return g_current_gl_context_tls ? g_current_gl_context_tls->Get() : nullptr; } void SetGLApi(GLApi* api) { @@ -404,7 +405,76 @@ RealGLApi::~RealGLApi() { } void RealGLApi::Initialize(DriverGL* driver) { + InitializeWithCommandLine(driver, base::CommandLine::ForCurrentProcess()); +} + +void RealGLApi::InitializeWithCommandLine(DriverGL* driver, + base::CommandLine* command_line) { + DCHECK(command_line); InitializeBase(driver); + + DCHECK(filtered_exts_.empty() && filtered_exts_str_.empty()); + + const std::string disabled_extensions = command_line->GetSwitchValueASCII( + switches::kDisableGLExtensions); + if (!disabled_extensions.empty()) { + std::vector disabled_extensions_vec; + Tokenize(disabled_extensions, ", ;", &disabled_extensions_vec); + + // Fill in filtered_exts_ vector first. + if (gfx::GetGLImplementation() != + gfx::kGLImplementationDesktopGLCoreProfile) { + const char* gl_extensions = reinterpret_cast( + GLApiBase::glGetStringFn(GL_EXTENSIONS)); + if (gl_extensions) + base::SplitString(gl_extensions, ' ', &filtered_exts_); + } else { + GLint num_extensions = 0; + GLApiBase::glGetIntegervFn(GL_NUM_EXTENSIONS, &num_extensions); + for (GLint i = 0; i < num_extensions; ++i) { + const char* gl_extension = reinterpret_cast( + GLApiBase::glGetStringiFn(GL_EXTENSIONS, i)); + DCHECK(gl_extension != NULL); + filtered_exts_.push_back(gl_extension); + } + } + + // Filter out extensions from the command line. + for (const std::string& disabled_ext : disabled_extensions_vec) { + filtered_exts_.erase(std::remove(filtered_exts_.begin(), + filtered_exts_.end(), + disabled_ext), + filtered_exts_.end()); + } + + // Construct filtered extensions string for GL_EXTENSIONS string lookups. + filtered_exts_str_ = JoinString(filtered_exts_, " "); + } +} + +void RealGLApi::glGetIntegervFn(GLenum pname, GLint* params) { + if (!filtered_exts_.empty() && pname == GL_NUM_EXTENSIONS) { + *params = static_cast(filtered_exts_.size()); + } else { + GLApiBase::glGetIntegervFn(pname, params); + } +} + +const GLubyte* RealGLApi::glGetStringFn(GLenum name) { + if (!filtered_exts_.empty() && name == GL_EXTENSIONS) { + return reinterpret_cast(filtered_exts_str_.c_str()); + } + return GLApiBase::glGetStringFn(name); +} + +const GLubyte* RealGLApi::glGetStringiFn(GLenum name, GLuint index) { + if (!filtered_exts_str_.empty() && name == GL_EXTENSIONS) { + if (index >= filtered_exts_.size()) { + return NULL; + } + return reinterpret_cast(filtered_exts_[index].c_str()); + } + return GLApiBase::glGetStringiFn(name, index); } void RealGLApi::glFlushFn() { diff --git a/ui/gl/gl_gl_api_implementation.h b/ui/gl/gl_gl_api_implementation.h index d4086006b6b5..e3d591dc3d24 100644 --- a/ui/gl/gl_gl_api_implementation.h +++ b/ui/gl/gl_gl_api_implementation.h @@ -5,10 +5,15 @@ #ifndef UI_GL_GL_GL_API_IMPLEMENTATION_H_ #define UI_GL_GL_GL_API_IMPLEMENTATION_H_ +#include + #include "base/compiler_specific.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_export.h" +namespace base { +class CommandLine; +} namespace gpu { namespace gles2 { class GLES2Decoder; @@ -33,7 +38,7 @@ void SetGLApi(GLApi* api); void SetGLApiToNoContext(); const GLVersionInfo* GetGLVersionInfo(); -class GLApiBase : public GLApi { +class GL_EXPORT GLApiBase : public GLApi { public: // Include the auto-generated part of this class. We split this because // it means we can easily edit the non-auto generated parts right here in @@ -49,15 +54,25 @@ class GLApiBase : public GLApi { }; // Implemenents the GL API by calling directly into the driver. -class RealGLApi : public GLApiBase { +class GL_EXPORT RealGLApi : public GLApiBase { public: RealGLApi(); ~RealGLApi() override; void Initialize(DriverGL* driver); + void InitializeWithCommandLine(DriverGL* driver, + base::CommandLine* command_line); + + void glGetIntegervFn(GLenum pname, GLint* params) override; + const GLubyte* glGetStringFn(GLenum name) override; + const GLubyte* glGetStringiFn(GLenum name, GLuint index) override; private: void glFinishFn() override; void glFlushFn() override; + + // Filtered GL_EXTENSIONS we return to glGetString(i) calls. + std::vector filtered_exts_; + std::string filtered_exts_str_; }; // Inserts a TRACE for every GL call. diff --git a/ui/gl/gl_switches.cc b/ui/gl/gl_switches.cc index 00d36d0d18ef..4ac132843d46 100644 --- a/ui/gl/gl_switches.cc +++ b/ui/gl/gl_switches.cc @@ -83,6 +83,9 @@ const char kDisableGLDrawingForTests[] = "disable-gl-drawing-for-tests"; const char kOverrideUseGLWithOSMesaForTests[] = "override-use-gl-with-osmesa-for-tests"; +// Disables specified comma separated GL Extensions if found. +const char kDisableGLExtensions[] = "disable-gl-extensions"; + // This is the list of switches passed from this file that are passed from the // GpuProcessHost to the GPU Process. Add your switch to this list if you need // to read it in the GPU process, else don't add it. diff --git a/ui/gl/gl_switches.h b/ui/gl/gl_switches.h index 15baa8e74591..05767db23434 100644 --- a/ui/gl/gl_switches.h +++ b/ui/gl/gl_switches.h @@ -44,6 +44,7 @@ GL_EXPORT extern const char kSwiftShaderPath[]; GL_EXPORT extern const char kTestGLLib[]; GL_EXPORT extern const char kUseGpuInTests[]; GL_EXPORT extern const char kEnableUnsafeES3APIs[]; +GL_EXPORT extern const char kDisableGLExtensions[]; // These flags are used by the test harness code, not passed in by users. GL_EXPORT extern const char kDisableGLDrawingForTests[]; diff --git a/ui/gl/gl_tests.gyp b/ui/gl/gl_tests.gyp index 193b6612ec80..bd92444561c0 100644 --- a/ui/gl/gl_tests.gyp +++ b/ui/gl/gl_tests.gyp @@ -12,11 +12,13 @@ 'type': '<(gtest_target_type)', 'sources': [ 'test/run_all_unittests.cc', + 'gl_api_unittest.cc', ], 'dependencies': [ '<(DEPTH)/base/base.gyp:base', '<(DEPTH)/base/base.gyp:test_support_base', '<(DEPTH)/testing/gtest.gyp:gtest', + 'gl.gyp:gl', ], 'conditions': [ ['OS == "android"', { -- 2.11.4.GIT