Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  GLContextProviderGLX.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */


#ifdef MOZ_WIDGET_GTK
#  include <gdk/gdk.h>
#  include <gdk/gdkx.h>
#  define GET_NATIVE_WINDOW(aWidget) \
    GDK_WINDOW_XID((GdkWindow*)aWidget->GetNativeData(NS_NATIVE_WINDOW))
#endif

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "X11UndefineNone.h"

#include "mozilla/MathAlgorithms.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/layers/CompositorOptions.h"
#include "mozilla/Range.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/Sprintf.h"
#include "mozilla/StaticPrefs_gfx.h"
#include "mozilla/StaticPrefs_layout.h"
#include "mozilla/widget/CompositorWidget.h"
#include "mozilla/widget/GtkCompositorWidget.h"
#include "mozilla/Unused.h"

#include "prenv.h"
#include "GLContextProvider.h"
#include "GLLibraryLoader.h"
#include "nsDebug.h"
#include "nsIWidget.h"
#include "GLXLibrary.h"
#include "gfxContext.h"
#include "gfxEnv.h"
#include "gfxPlatform.h"
#include "GLContextGLX.h"
#include "gfxUtils.h"
#include "gfx2DGlue.h"
#include "GLScreenBuffer.h"

#include "gfxCrashReporterUtils.h"

#ifdef MOZ_WIDGET_GTK
#  include "gfxPlatformGtk.h"
#endif

namespace mozilla::gl {

using namespace mozilla::gfx;
using namespace mozilla::widget;

MOZ_RUNINIT GLXLibrary sGLXLibrary;

static inline bool HasExtension(const char* aExtensions,
                                const char* aRequiredExtension) {
  return GLContext::ListHasExtension(
      reinterpret_cast<const GLubyte*>(aExtensions), aRequiredExtension);
}

bool GLXLibrary::EnsureInitialized(Display* aDisplay) {
  if (mInitialized) {
    return true;
  }

  // Don't repeatedly try to initialize.
  if (mTriedInitializing) {
    return false;
  }
  mTriedInitializing = true;

  MOZ_ASSERT(aDisplay);
  if (!aDisplay) {
    return false;
  }

  // Force enabling s3 texture compression. (Bug 774134)
  PR_SetEnv("force_s3tc_enable=true");

  if (!mOGLLibrary) {
    // see e.g. bug 608526: it is intrinsically interesting to know whether we
    // have dynamically linked to libGL.so.1 because at least the NVIDIA
    // implementation requires an executable stack, which causes mprotect calls,
    // which trigger glibc bug
    // http://sourceware.org/bugzilla/show_bug.cgi?id=12225
    const char* libGLfilename = "libGL.so.1";
#if defined(__OpenBSD__) || defined(__NetBSD__)
    libGLfilename = "libGL.so";
#endif

    const bool forceFeatureReport = false;
    ScopedGfxFeatureReporter reporter(libGLfilename, forceFeatureReport);
    mOGLLibrary = PR_LoadLibrary(libGLfilename);
    if (!mOGLLibrary) {
      NS_WARNING("Couldn't load OpenGL shared library.");
      return false;
    }
    reporter.SetSuccessful();
  }

  if (gfxEnv::MOZ_GLX_DEBUG()) {
    mDebug = true;
  }

#define SYMBOL(X)                 \
  {                               \
    (PRFuncPtr*)&mSymbols.f##X, { \
      { "glX" #X }                \
    }                             \
  }
#define END_OF_SYMBOLS \
  {                    \
    nullptr, {}        \
  }

  const SymLoadStruct symbols[] = {
      /* functions that were in GLX 1.0 */
      SYMBOL(DestroyContext),
      SYMBOL(MakeCurrent),
      SYMBOL(SwapBuffers),
      SYMBOL(QueryVersion),
      SYMBOL(GetConfig),
      SYMBOL(GetCurrentContext),
      SYMBOL(WaitGL),
      SYMBOL(WaitX),

      /* functions introduced in GLX 1.1 */
      SYMBOL(QueryExtensionsString),
      SYMBOL(GetClientString),
      SYMBOL(QueryServerString),

      /* functions introduced in GLX 1.3 */
      SYMBOL(ChooseFBConfig),
      SYMBOL(ChooseVisual),
      SYMBOL(GetFBConfigAttrib),
      SYMBOL(GetFBConfigs),
      SYMBOL(CreatePixmap),
      SYMBOL(DestroyPixmap),
      SYMBOL(CreateNewContext),

      // Core in GLX 1.4, ARB extension before.
      {(PRFuncPtr*)&mSymbols.fGetProcAddress,
       {{"glXGetProcAddress""glXGetProcAddressARB"}}},
      END_OF_SYMBOLS};

  {
    const SymbolLoader libLoader(*mOGLLibrary);
    if (!libLoader.LoadSymbols(symbols)) {
      NS_WARNING("Couldn't load required GLX symbols.");
      return false;
    }
  }
  const SymbolLoader pfnLoader(mSymbols.fGetProcAddress);

  int screen = DefaultScreen(aDisplay);

  {
    int major, minor;
    if (!fQueryVersion(aDisplay, &major, &minor) || major != 1 || minor < 3) {
      NS_ERROR("GLX version older than 1.3. (released in 1998)");
      return false;
    }
  }

  const SymLoadStruct symbols_createcontext[] = {
      SYMBOL(CreateContextAttribsARB), END_OF_SYMBOLS};

  const SymLoadStruct symbols_videosync[] = {
      SYMBOL(GetVideoSyncSGI), SYMBOL(WaitVideoSyncSGI), END_OF_SYMBOLS};

  const SymLoadStruct symbols_swapcontrol[] = {SYMBOL(SwapIntervalEXT),
                                               END_OF_SYMBOLS};

  const SymLoadStruct symbols_querydrawable[] = {SYMBOL(QueryDrawable),
                                                 END_OF_SYMBOLS};

  const auto fnLoadSymbols = [&](const SymLoadStruct* symbols) {
    if (pfnLoader.LoadSymbols(symbols)) return true;

    ClearSymbols(symbols);
    return false;
  };

  const char* clientVendor = fGetClientString(aDisplay, LOCAL_GLX_VENDOR);
  const char* serverVendor =
      fQueryServerString(aDisplay, screen, LOCAL_GLX_VENDOR);
  const char* extensionsStr = fQueryExtensionsString(aDisplay, screen);

  if (HasExtension(extensionsStr, "GLX_ARB_create_context") &&
      HasExtension(extensionsStr, "GLX_ARB_create_context_profile") &&
      fnLoadSymbols(symbols_createcontext)) {
    mHasCreateContextAttribs = true;
  }

  if (HasExtension(extensionsStr, "GLX_ARB_create_context_robustness")) {
    mHasRobustness = true;
  }

  if (HasExtension(extensionsStr, "GLX_NV_robustness_video_memory_purge")) {
    mHasVideoMemoryPurge = true;
  }

  if (HasExtension(extensionsStr, "GLX_SGI_video_sync") &&
      fnLoadSymbols(symbols_videosync)) {
    mHasVideoSync = true;
  }

  if (!HasExtension(extensionsStr, "GLX_EXT_swap_control") ||
      !fnLoadSymbols(symbols_swapcontrol)) {
    NS_WARNING(
        "GLX_swap_control unsupported, ASAP mode may still block on buffer "
        "swaps.");
  }

  if (HasExtension(extensionsStr, "GLX_EXT_buffer_age") &&
      fnLoadSymbols(symbols_querydrawable)) {
    mHasBufferAge = true;
  }

  mIsATI = serverVendor && DoesStringMatch(serverVendor, "ATI");
  mIsNVIDIA =
      serverVendor && DoesStringMatch(serverVendor, "NVIDIA Corporation");
  mClientIsMesa = clientVendor && DoesStringMatch(clientVendor, "Mesa");

  mInitialized = true;

  // This needs to be after `fQueryServerString` is called so that the
  // driver is loaded.
  MesaMemoryLeakWorkaround();

  return true;
}

bool GLXLibrary::SupportsVideoSync(Display* aDisplay) {
  if (!EnsureInitialized(aDisplay)) {
    return false;
  }

  return mHasVideoSync;
}

static int (*sOldErrorHandler)(Display*, XErrorEvent*);
static XErrorEvent sErrorEvent = {};

static int GLXErrorHandler(Display* display, XErrorEvent* ev) {
  if (!sErrorEvent.error_code) {
    sErrorEvent = *ev;
  }
  return 0;
}

GLXLibrary::WrapperScope::WrapperScope(const GLXLibrary& glx,
                                       const charconst funcName,
                                       Display* aDisplay)
    : mGlx(glx), mFuncName(funcName), mDisplay(aDisplay) {
  if (mGlx.mDebug) {
    sOldErrorHandler = XSetErrorHandler(GLXErrorHandler);
  }
}

GLXLibrary::WrapperScope::~WrapperScope() {
  if (mGlx.mDebug) {
    if (mDisplay) {
      FinishX(mDisplay);
    }
    if (sErrorEvent.error_code) {
      char buffer[100] = {};
      if (mDisplay) {
        XGetErrorText(mDisplay, sErrorEvent.error_code, buffer, sizeof(buffer));
      } else {
        SprintfLiteral(buffer, "%d", sErrorEvent.error_code);
      }
      printf_stderr("X ERROR after %s: %s (%i) - Request: %i.%i, Serial: %lu",
                    mFuncName, buffer, sErrorEvent.error_code,
                    sErrorEvent.request_code, sErrorEvent.minor_code,
                    sErrorEvent.serial);
      MOZ_ASSERT_UNREACHABLE("AfterGLXCall sErrorEvent");
    }
    const auto was = XSetErrorHandler(sOldErrorHandler);
    if (was != GLXErrorHandler) {
      NS_WARNING("Concurrent XSetErrorHandlers");
    }
  }
}

// Returns the GTK display if available; otherwise, if a display was
// previously opened by this method and is still open, returns a
// reference to it; otherwise, opens a new connection.  (The non-GTK
// cases are similar to what we do for EGL.)
std::shared_ptr<XlibDisplay> GLXLibrary::GetDisplay() {
  std::shared_ptr<XlibDisplay> display;

#ifdef MOZ_WIDGET_GTK
  static const bool kHaveGtk = !!gdk_display_get_default();
  if (kHaveGtk) {
    display = XlibDisplay::Borrow(DefaultXDisplay());
  }
#endif
  if (display) {
    return display;
  }

  auto ownDisplay = mOwnDisplay.Lock();
  display = ownDisplay->lock();
  if (display) {
    return display;
  }

  display = XlibDisplay::Open(nullptr);
  if (NS_WARN_IF(!display)) {
    return nullptr;
  }
  *ownDisplay = display;
  return display;
}

already_AddRefed<GLContextGLX> GLContextGLX::CreateGLContext(
    const GLContextDesc& desc, std::shared_ptr<XlibDisplay> display,
    GLXDrawable drawable, GLXFBConfig cfg, Drawable ownedPixmap) {
  GLXLibrary& glx = sGLXLibrary;

  int isDoubleBuffered = 0;
  int err = glx.fGetFBConfigAttrib(*display, cfg, LOCAL_GLX_DOUBLEBUFFER,
                                   &isDoubleBuffered);
  if (LOCAL_GLX_BAD_ATTRIBUTE != err) {
    if (ShouldSpew()) {
      printf("[GLX] FBConfig is %sdouble-buffered\n",
             isDoubleBuffered ? "" : "not ");
    }
  }

  if (!glx.HasCreateContextAttribs()) {
    NS_WARNING("Cannot create GLContextGLX without glxCreateContextAttribs");
    return nullptr;
  }

  // -

  const auto CreateWithAttribs =
      [&](const std::vector<int>& attribs) -> RefPtr<GLContextGLX> {
    auto terminated = attribs;
    terminated.push_back(0);

    const auto glxContext = glx.fCreateContextAttribs(
        *display, cfg, nullptr, X11True, terminated.data());
    if (!glxContext) return nullptr;
    const RefPtr<GLContextGLX> ret = new GLContextGLX(
        desc, display, drawable, glxContext, isDoubleBuffered, ownedPixmap);

    if (!ret->Init()) return nullptr;

    return ret;
  };

  // -

  RefPtr<GLContextGLX> glContext;

  std::vector<int> attribs;
  attribs.insert(attribs.end(), {
                                    LOCAL_GLX_RENDER_TYPE,
                                    LOCAL_GLX_RGBA_TYPE,
                                });
  if (glx.HasVideoMemoryPurge()) {
    attribs.insert(attribs.end(),
                   {
                       LOCAL_GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV,
                       LOCAL_GL_TRUE,
                   });
  }
  const bool useCore =
      !(desc.flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE);
  if (useCore) {
    attribs.insert(attribs.end(), {
                                      LOCAL_GLX_CONTEXT_MAJOR_VERSION_ARB,
                                      3,
                                      LOCAL_GLX_CONTEXT_MINOR_VERSION_ARB,
                                      2,
                                      LOCAL_GLX_CONTEXT_PROFILE_MASK_ARB,
                                      LOCAL_GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
                                  });
  }

  if (glx.HasRobustness()) {
    auto withRobustness = attribs;
    withRobustness.insert(withRobustness.end(),
                          {
                              LOCAL_GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
                              LOCAL_GLX_LOSE_CONTEXT_ON_RESET_ARB,
                          });

    {
      auto withRBAB = withRobustness;
      withRBAB.insert(withRBAB.end(),
                      {
                          LOCAL_GLX_CONTEXT_FLAGS_ARB,
                          LOCAL_GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB,
                      });
      if (!glContext) {
        glContext = CreateWithAttribs(withRBAB);
        if (!glContext) {
          NS_WARNING("Failed to create+init GLContextGLX with RBAB");
        }
      }
    }

    if (!glContext) {
      glContext = CreateWithAttribs(withRobustness);
      if (!glContext) {
        NS_WARNING("Failed to create+init GLContextGLX with Robustness");
      }
    }
  }

  if (!glContext) {
    glContext = CreateWithAttribs(attribs);
    if (!glContext) {
      NS_WARNING("Failed to create+init GLContextGLX with required attribs");
    }
  }

  return glContext.forget();
}

GLContextGLX::~GLContextGLX() {
  MarkDestroyed();

  // Wrapped context should not destroy glxContext/Surface
  if (!mOwnsContext) {
    return;
  }

  // see bug 659842 comment 76
  bool success = mGLX->fMakeCurrent(*mDisplay, X11None, nullptr);
  if (!success) {
    NS_WARNING(
        "glXMakeCurrent failed to release GL context before we call "
        "glXDestroyContext!");
  }

  mGLX->fDestroyContext(*mDisplay, mContext);

  // If we own the enclosed X pixmap, then free it after we free the enclosing
  // GLX pixmap.
  if (mOwnedPixmap) {
    mGLX->fDestroyPixmap(*mDisplay, mDrawable);
    XFreePixmap(*mDisplay, mOwnedPixmap);
  }
}

bool GLContextGLX::Init() {
  if (!GLContext::Init()) {
    return false;
  }

  // EXT_framebuffer_object is not supported on Core contexts
  // so we'll also check for ARB_framebuffer_object
  if (!IsExtensionSupported(EXT_framebuffer_object) &&
      !IsSupported(GLFeature::framebuffer_object))
    return false;

  return true;
}

bool GLContextGLX::MakeCurrentImpl() const {
  if (mGLX->IsMesa()) {
    // Read into the event queue to ensure that Mesa receives a
    // DRI2InvalidateBuffers event before drawing. See bug 1280653.
    Unused << XPending(*mDisplay);
  }

  const bool succeeded = mGLX->fMakeCurrent(*mDisplay, mDrawable, mContext);
  if (!succeeded) {
    NS_WARNING("Failed to make GL context current!");
  }

  if (!IsOffscreen() && mGLX->SupportsSwapControl()) {
    // Many GLX implementations default to blocking until the next
    // VBlank when calling glXSwapBuffers. We want to run unthrottled
    // in ASAP mode. See bug 1280744.
    const bool swapInterval = gfxVars::SwapIntervalGLX();
    const bool isASAP = (StaticPrefs::layout_frame_rate() == 0);
    const int interval = (swapInterval && !isASAP) ? 1 : 0;
    mGLX->fSwapInterval(*mDisplay, mDrawable, interval);
  }
  return succeeded;
}

bool GLContextGLX::IsCurrentImpl() const {
  return mGLX->fGetCurrentContext() == mContext;
}

Maybe<SymbolLoader> GLContextGLX::GetSymbolLoader() const {
  const auto pfn = sGLXLibrary.GetGetProcAddress();
  return Some(SymbolLoader(pfn));
}

bool GLContextGLX::IsDoubleBuffered() const { return mDoubleBuffered; }

bool GLContextGLX::SwapBuffers() {
  if (!mDoubleBuffered) return false;
  mGLX->fSwapBuffers(*mDisplay, mDrawable);
  return true;
}

GLint GLContextGLX::GetBufferAge() const {
  if (!sGLXLibrary.SupportsBufferAge()) {
    return 0;
  }

  GLuint result = 0;
  mGLX->fQueryDrawable(*mDisplay, mDrawable, LOCAL_GLX_BACK_BUFFER_AGE_EXT,
                       &result);
  if (result > INT32_MAX) {
    // If the result can't fit, just assume the buffer cannot be reused.
    return 0;
  }
  return result;
}

void GLContextGLX::GetWSIInfo(nsCString* const out) const {
  int screen = DefaultScreen(mDisplay->get());

  int majorVersion, minorVersion;
  sGLXLibrary.fQueryVersion(*mDisplay, &majorVersion, &minorVersion);

  out->Append(nsPrintfCString("GLX %u.%u", majorVersion, minorVersion));

  out->AppendLiteral("\nGLX_VENDOR(client): ");
  out->Append(sGLXLibrary.fGetClientString(*mDisplay, LOCAL_GLX_VENDOR));

  out->AppendLiteral("\nGLX_VENDOR(server): ");
  out->Append(
      sGLXLibrary.fQueryServerString(*mDisplay, screen, LOCAL_GLX_VENDOR));

  out->AppendLiteral("\nExtensions: ");
  out->Append(sGLXLibrary.fQueryExtensionsString(*mDisplay, screen));
}

bool GLContextGLX::OverrideDrawable(GLXDrawable drawable) {
  return mGLX->fMakeCurrent(*mDisplay, drawable, mContext);
}

bool GLContextGLX::RestoreDrawable() {
  return mGLX->fMakeCurrent(*mDisplay, mDrawable, mContext);
}

GLContextGLX::GLContextGLX(const GLContextDesc& desc,
                           std::shared_ptr<XlibDisplay> aDisplay,
                           GLXDrawable aDrawable, GLXContext aContext,
                           bool aDoubleBuffered, Drawable aOwnedPixmap)
    : GLContext(desc, nullptr),
      mContext(aContext),
      mDisplay(aDisplay),
      mDrawable(aDrawable),
      mOwnedPixmap(aOwnedPixmap),
      mDoubleBuffered(aDoubleBuffered),
      mGLX(&sGLXLibrary) {}

static bool AreCompatibleVisuals(Visual* one, Visual* two) {
  if (one->c_class != two->c_class) {
    return false;
  }

  if (one->red_mask != two->red_mask || one->green_mask != two->green_mask ||
      one->blue_mask != two->blue_mask) {
    return false;
  }

  if (one->bits_per_rgb != two->bits_per_rgb) {
    return false;
  }

  return true;
}

already_AddRefed<GLContext> CreateForWidget(Display* aXDisplay, Window aXWindow,
                                            bool aHardwareWebRender,
                                            bool aForceAccelerated) {
  if (!sGLXLibrary.EnsureInitialized(aXDisplay)) {
    return nullptr;
  }

  // Currently, we take whatever Visual the window already has, and
  // try to create an fbconfig for that visual.  This isn't
  // necessarily what we want in the long run; an fbconfig may not
  // be available for the existing visual, or if it is, the GL
  // performance might be suboptimal.  But using the existing visual
  // is a relatively safe intermediate step.

  if (!aXDisplay) {
    NS_ERROR("X Display required for GLX Context provider");
    return nullptr;
  }

  if (!aXWindow) {
    NS_ERROR("X window required for GLX Context provider");
    return nullptr;
  }

  int xscreen = DefaultScreen(aXDisplay);

  GLXFBConfig config;
  int visid;
  if (!GLContextGLX::FindFBConfigForWindow(
          aXDisplay, xscreen, aXWindow, &config, &visid, aHardwareWebRender)) {
    return nullptr;
  }

  CreateContextFlags flags;
  if (aHardwareWebRender) {
    flags = CreateContextFlags::NONE;  // WR needs GL3.2+
  } else {
    flags = CreateContextFlags::REQUIRE_COMPAT_PROFILE;
  }
  return GLContextGLX::CreateGLContext(
      {{flags}, false}, XlibDisplay::Borrow(aXDisplay), aXWindow, config);
}

already_AddRefed<GLContext> GLContextProviderGLX::CreateForCompositorWidget(
    CompositorWidget* aCompositorWidget, bool aHardwareWebRender,
    bool aForceAccelerated) {
  if (!aCompositorWidget) {
    MOZ_ASSERT(false);
    return nullptr;
  }
  GtkCompositorWidget* compWidget = aCompositorWidget->AsGTK();
  MOZ_ASSERT(compWidget);

  return CreateForWidget(DefaultXDisplay(), compWidget->XWindow(),
                         aHardwareWebRender, aForceAccelerated);
}

static bool ChooseConfig(GLXLibrary* glx, Display* display, int screen,
                         GLXFBConfig* const out_config, intconst out_visid) {
  const int attribs[] = {
      LOCAL_GLX_RENDER_TYPE,
      LOCAL_GLX_RGBA_BIT,
      LOCAL_GLX_DRAWABLE_TYPE,
      LOCAL_GLX_PIXMAP_BIT,
      LOCAL_GLX_X_RENDERABLE,
      X11True,
      LOCAL_GLX_RED_SIZE,
      8,
      LOCAL_GLX_GREEN_SIZE,
      8,
      LOCAL_GLX_BLUE_SIZE,
      8,
      LOCAL_GLX_ALPHA_SIZE,
      8,
      LOCAL_GLX_DEPTH_SIZE,
      0,
      LOCAL_GLX_STENCIL_SIZE,
      0,
      0,
  };

  int numConfigs = 0;
  const auto scopedConfigArr =
      glx->fChooseFBConfig(display, screen, attribs, &numConfigs);
  const auto freeConfigList = MakeScopeExit([&]() {
    if (scopedConfigArr) {
      XFree(scopedConfigArr);
    }
  });
  if (!scopedConfigArr || !numConfigs) return false;

  // Issues with glxChooseFBConfig selection and sorting:
  // * ALPHA_SIZE is sorted as 'largest total RGBA bits first'. If we don't
  // request
  //   alpha bits, we'll probably get RGBA anyways, since 32 is more than 24.
  // * DEPTH_SIZE is sorted largest first, including for `0` inputs.
  // * STENCIL_SIZE is smallest first, but it might return `8` even though we
  // ask for
  //   `0`.

  // For now, we don't care about these. We *will* care when we do XPixmap
  // sharing.

  for (int i = 0; i < numConfigs; ++i) {
    GLXFBConfig curConfig = scopedConfigArr[i];

    int visid;
    if (glx->fGetFBConfigAttrib(display, curConfig, LOCAL_GLX_VISUAL_ID,
                                &visid) != Success) {
      continue;
    }

    if (!visid) continue;

    *out_config = curConfig;
    *out_visid = visid;
    return true;
  }

  return false;
}

bool GLContextGLX::FindVisual(Display* display, int screen,
                              intconst out_visualId) {
  if (!sGLXLibrary.EnsureInitialized(display)) {
    return false;
  }

  XVisualInfo visualTemplate;
  visualTemplate.screen = screen;

  // Get all visuals of screen

  int visualsLen = 0;
  XVisualInfo* xVisuals =
      XGetVisualInfo(display, VisualScreenMask, &visualTemplate, &visualsLen);
  if (!xVisuals) {
    return false;
  }
  const Range<XVisualInfo> visualInfos(xVisuals, visualsLen);
  auto cleanupVisuals = MakeScopeExit([&] { XFree(xVisuals); });

  // Get default visual info

  Visual* defaultVisual = DefaultVisual(display, screen);
  const auto defaultVisualInfo = [&]() -> const XVisualInfo* {
    for (const auto& cur : visualInfos) {
      if (cur.visual == defaultVisual) {
        return &cur;
      }
    }
    return nullptr;
  }();
  if (!defaultVisualInfo) {
    MOZ_ASSERT(false);
    return false;
  }

  const int bpp = 32;

  for (auto& cur : visualInfos) {
    const auto fnConfigMatches = [&](const int pname, const int expected) {
      int actual;
      if (sGLXLibrary.fGetConfig(display, &cur, pname, &actual)) {
        return false;
      }
      return actual == expected;
    };

    // Check if visual is compatible.
    if (cur.depth != bpp || cur.c_class != defaultVisualInfo->c_class) {
      continue;
    }

    // Check if visual is compatible to GL requests.
    if (fnConfigMatches(LOCAL_GLX_USE_GL, 1) &&
        fnConfigMatches(LOCAL_GLX_DOUBLEBUFFER, 1) &&
        fnConfigMatches(LOCAL_GLX_RED_SIZE, 8) &&
        fnConfigMatches(LOCAL_GLX_GREEN_SIZE, 8) &&
        fnConfigMatches(LOCAL_GLX_BLUE_SIZE, 8) &&
        fnConfigMatches(LOCAL_GLX_ALPHA_SIZE, 8)) {
      *out_visualId = cur.visualid;
      return true;
    }
  }

  return false;
}

bool GLContextGLX::FindFBConfigForWindow(Display* display, int screen,
                                         Window window,
                                         GLXFBConfig* const out_config,
                                         intconst out_visid,
                                         bool aWebRender) {
  // XXX the visual ID is almost certainly the LOCAL_GLX_FBCONFIG_ID, so
  // we could probably do this first and replace the glXGetFBConfigs
  // with glXChooseConfigs.  Docs are sparklingly clear as always.
  XWindowAttributes windowAttrs;
  if (!XGetWindowAttributes(display, window, &windowAttrs)) {
    NS_WARNING("[GLX] XGetWindowAttributes() failed");
    return false;
  }

  GLXFBConfig* cfgs = nullptr;
  const auto freeConfigList = MakeScopeExit([&]() {
    if (cfgs) {
      XFree(cfgs);
    }
  });
  int numConfigs;
  const int webrenderAttribs[] = {LOCAL_GLX_ALPHA_SIZE,
                                  windowAttrs.depth == 32 ? 8 : 0,
                                  LOCAL_GLX_DOUBLEBUFFER, X11True, 0};

  if (aWebRender) {
    cfgs = sGLXLibrary.fChooseFBConfig(display, screen, webrenderAttribs,
                                       &numConfigs);
  } else {
    cfgs = sGLXLibrary.fGetFBConfigs(display, screen, &numConfigs);
  }

  if (!cfgs) {
    NS_WARNING("[GLX] glXGetFBConfigs() failed");
    return false;
  }
  NS_ASSERTION(numConfigs > 0, "No FBConfigs found!");

  const VisualID windowVisualID = XVisualIDFromVisual(windowAttrs.visual);
#ifdef DEBUG
  printf("[GLX] window %lx has VisualID 0x%lx\n", window, windowVisualID);
#endif

  for (int i = 0; i < numConfigs; i++) {
    int visid = X11None;
    sGLXLibrary.fGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID,
                                   &visid);
    if (visid) {
      // WebRender compatible GLX visual is configured
      // at nsWindow::Create() by GLContextGLX::FindVisual(),
      // just reuse it here.
      if (windowVisualID == static_cast<VisualID>(visid)) {
        *out_config = cfgs[i];
        *out_visid = visid;
        return true;
      }
    }
  }

  // We don't have a frame buffer visual which matches the GLX visual
  // from GLContextGLX::FindVisual(). Let's try to find a near one and hope
  // we're not on NVIDIA (Bug 1478454) as it causes X11 BadMatch error there.
  for (int i = 0; i < numConfigs; i++) {
    int visid = X11None;
    sGLXLibrary.fGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID,
                                   &visid);
    if (visid) {
      int depth;
      Visual* visual;
      FindVisualAndDepth(display, visid, &visual, &depth);
      if (depth == windowAttrs.depth &&
          AreCompatibleVisuals(windowAttrs.visual, visual)) {
        *out_config = cfgs[i];
        *out_visid = visid;
        return true;
      }
    }
  }

  NS_WARNING("[GLX] Couldn't find a FBConfig matching window visual");
  return false;
}

static already_AddRefed<GLContextGLX> CreateOffscreenPixmapContext(
    const GLContextCreateDesc& desc, const IntSize& size,
    nsACString* const out_failureId) {
  GLXLibrary* glx = &sGLXLibrary;
  auto display = glx->GetDisplay();

  if (!display || !glx->EnsureInitialized(*display)) return nullptr;

  int screen = DefaultScreen(display->get());

  GLXFBConfig config;
  int visid;
  if (!ChooseConfig(glx, *display, screen, &config, &visid)) {
    NS_WARNING("Failed to find a compatible config.");
    return nullptr;
  }

  Visual* visual;
  int depth;
  FindVisualAndDepth(*display, visid, &visual, &depth);

  gfx::IntSize dummySize(16, 16);
  const auto drawable =
      XCreatePixmap(*display, DefaultRootWindow(display->get()),
                    dummySize.width, dummySize.height, depth);
  if (!drawable) {
    return nullptr;
  }

  // Handle slightly different signature between glXCreatePixmap and
  // its pre-GLX-1.3 extension equivalent (though given the ABI, we
  // might not need to).
  const auto pixmap = glx->fCreatePixmap(*display, config, drawable, nullptr);
  if (pixmap == 0) {
    XFreePixmap(*display, drawable);
    return nullptr;
  }

  auto fullDesc = GLContextDesc{desc};
  fullDesc.isOffscreen = true;

  return GLContextGLX::CreateGLContext(fullDesc, display, pixmap, config,
                                       drawable);
}

/*static*/
already_AddRefed<GLContext> GLContextProviderGLX::CreateHeadless(
    const GLContextCreateDesc& desc, nsACString* const out_failureId) {
  IntSize dummySize = IntSize(16, 16);
  return CreateOffscreenPixmapContext(desc, dummySize, out_failureId);
}

/*static*/
GLContext* GLContextProviderGLX::GetGlobalContext() {
  // Context sharing not supported.
  return nullptr;
}

/*static*/
void GLContextProviderGLX::Shutdown() {}

}  // namespace mozilla::gl

Messung V0.5
C=91 H=98 G=94

¤ Dauer der Verarbeitung: 0.24 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge