| // Copyright 2017 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_context_glx.h" |
| |
| #include "base/memory/scoped_refptr.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/gfx/x/x11.h" |
| #include "ui/gfx/x/x11_error_tracker.h" |
| #include "ui/gfx/x/x11_types.h" |
| #include "ui/gl/gl_surface_glx_x11.h" |
| #include "ui/gl/init/gl_factory.h" |
| #include "ui/gl/test/gl_image_test_support.h" |
| |
| namespace gl { |
| |
| TEST(GLContextGLXTest, DoNotDestroyOnFailedMakeCurrent) { |
| auto* xdisplay = gfx::GetXDisplay(); |
| ASSERT_TRUE(xdisplay); |
| |
| gfx::X11ErrorTracker error_tracker; |
| |
| XSetWindowAttributes swa; |
| memset(&swa, 0, sizeof(swa)); |
| swa.background_pixmap = 0; |
| swa.override_redirect = x11::True; |
| auto xwindow = XCreateWindow(xdisplay, DefaultRootWindow(xdisplay), 0, 0, 10, |
| 10, // x, y, width, height |
| 0, // border width |
| CopyFromParent, // depth |
| InputOutput, |
| CopyFromParent, // visual |
| CWBackPixmap | CWOverrideRedirect, &swa); |
| XSelectInput(xdisplay, xwindow, StructureNotifyMask); |
| |
| XEvent xevent; |
| XMapWindow(xdisplay, xwindow); |
| // Wait until the window is mapped. |
| while (XNextEvent(xdisplay, &xevent) && xevent.type != MapNotify && |
| xevent.xmap.window != xwindow) { |
| } |
| |
| GLImageTestSupport::InitializeGL(base::nullopt); |
| auto surface = |
| gl::InitializeGLSurface(base::MakeRefCounted<GLSurfaceGLXX11>(xwindow)); |
| scoped_refptr<GLContext> context = |
| gl::init::CreateGLContext(nullptr, surface.get(), GLContextAttribs()); |
| |
| // Verify that MakeCurrent() is successful. |
| ASSERT_TRUE(context->GetHandle()); |
| ASSERT_TRUE(context->MakeCurrent(surface.get())); |
| EXPECT_TRUE(context->GetHandle()); |
| |
| // Destroy the window, and wait until the window is unmapped. There should be |
| // no x11 errors. |
| context->ReleaseCurrent(surface.get()); |
| XDestroyWindow(xdisplay, xwindow); |
| while (XNextEvent(xdisplay, &xevent) && xevent.type != UnmapNotify) { |
| } |
| ASSERT_FALSE(error_tracker.FoundNewError()); |
| |
| if (context->MakeCurrent(surface.get())) { |
| // With some drivers, MakeCurrent() does not fail for an already-destroyed |
| // window. In those cases, override the glx api to force MakeCurrent() to |
| // fail. |
| context->ReleaseCurrent(surface.get()); |
| auto real_fn = g_driver_glx.fn.glXMakeContextCurrentFn; |
| g_driver_glx.fn.glXMakeContextCurrentFn = |
| [](Display* display, GLXDrawable drawable, GLXDrawable read, |
| GLXContext context) -> int { return 0; }; |
| EXPECT_FALSE(context->MakeCurrent(surface.get())); |
| g_driver_glx.fn.glXMakeContextCurrentFn = real_fn; |
| } |
| // At this point, MakeCurrent() failed. Make sure the GLContextGLX still was |
| // not destroyed. |
| ASSERT_TRUE(context->GetHandle()); |
| surface = nullptr; |
| XSync(xdisplay, x11::True); |
| } |
| |
| } // namespace gl |