Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/vcl/source/opengl/x11/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 13 kB image not shown  

Quelle  context.cxx   Sprache: C

 
/* -*- 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 <memory>
#include <tools/lazydelete.hxx>
#include <vcl/syschild.hxx>

#include <svdata.hxx>

#include <unx/saldisp.hxx>
#include <unx/salframe.h>
#include <unx/salgdi.h>
#include <unx/salinst.h>
#include <unx/salvd.h>
#include <unx/x11/xlimits.hxx>

#include <opengl/zone.hxx>

#include <vcl/opengl/OpenGLContext.hxx>
#include <vcl/opengl/OpenGLHelper.hxx>
#include <sal/log.hxx>
#include <o3tl/string_view.hxx>

static std::vector<GLXContext> g_vShareList;
static bool g_bAnyCurrent;

namespace {

class X11OpenGLContext : public OpenGLContext
{
public:
    virtual void initWindow() override;
private:
    GLX11Window m_aGLWin;
    virtual const GLWindow& getOpenGLWindow() const override { return m_aGLWin; }
    virtual GLWindow& getModifiableOpenGLWindow() override { return m_aGLWin; }
    virtual bool ImplInit() override;
    void initGLWindow(Visual* pVisual);
    virtual SystemWindowData generateWinData(vcl::Window* pParent, bool bRequestLegacyContext) override;
    virtual void makeCurrent() override;
    virtual void destroyCurrentContext() override;
    virtual bool isCurrent() override;
    virtual bool isAnyCurrent() override;
    virtual void sync() override;
    virtual void resetCurrent() override;
    virtual void swapBuffers() override;
};

#ifdef DBG_UTIL
    int unxErrorHandler(Display* dpy, XErrorEvent* event)
    {
        char err[256];
        char req[256];
        char minor[256];
        XGetErrorText(dpy, event->error_code, err, 256);
        XGetErrorText(dpy, event->request_code, req, 256);
        XGetErrorText(dpy, event->minor_code, minor, 256);
        SAL_WARN("vcl.opengl""Error: " << err << ", Req: " << req << ", Minor: " << minor);
        return 0;
    }
#endif

    typedef int (*errorHandler)(Display* /*dpy*/, XErrorEvent* /*evnt*/);

    class TempErrorHandler
    {
    private:
        errorHandler oldErrorHandler;
        Display* mdpy;

    public:
        TempErrorHandler(Display* dpy, errorHandler newErrorHandler)
            : oldErrorHandler(nullptr)
            , mdpy(dpy)
        {
            if (mdpy)
            {
                XLockDisplay(dpy);
                XSync(dpy, false);
                oldErrorHandler = XSetErrorHandler(newErrorHandler);
            }
        }

        ~TempErrorHandler()
        {
            if (mdpy)
            {
                // sync so that we possibly get an XError
                glXWaitGL();
                XSync(mdpy, false);
                XSetErrorHandler(oldErrorHandler);
                XUnlockDisplay(mdpy);
            }
        }
    };

    bool errorTriggered;
    int oglErrorHandler( Display* /*dpy*/, XErrorEvent* /*evnt*/ )
    {
        errorTriggered = true;

        return 0;
    }

    GLXFBConfig* getFBConfig(Display* dpy, Window win, int& nBestFBC)
    {
        OpenGLZone aZone;

        if( dpy == nullptr || !glXQueryExtension( dpy, nullptr, nullptr ) )
            return nullptr;

        VCL_GL_INFO("window: " << win);

        XWindowAttributes xattr;
        if( !XGetWindowAttributes( dpy, win, &xattr ) )
        {
            SAL_WARN("vcl.opengl""Failed to get window attributes for fbconfig " << win);
            xattr.screen = nullptr;
            xattr.visual = nullptr;
        }

        int screen = XScreenNumberOfScreen( xattr.screen );

        // TODO: moggi: Select colour channel depth based on visual attributes, not hardcoded */
        static int visual_attribs[] =
        {
            GLX_DOUBLEBUFFER,       True,
            GLX_X_RENDERABLE,       True,
            GLX_RED_SIZE,           8,
            GLX_GREEN_SIZE,         8,
            GLX_BLUE_SIZE,          8,
            GLX_ALPHA_SIZE,         8,
            GLX_DEPTH_SIZE,         24,
            GLX_X_VISUAL_TYPE,      GLX_TRUE_COLOR,
            None
        };

        int fbCount = 0;
        GLXFBConfig* pFBC = glXChooseFBConfig( dpy,
                screen,
                visual_attribs, &fbCount );

        if(!pFBC)
        {
            SAL_WARN("vcl.opengl""no suitable fb format found");
            return nullptr;
        }

        int best_num_samp = -1;
        for(int i = 0; i < fbCount; ++i)
        {
            XVisualInfo* pVi = glXGetVisualFromFBConfig( dpy, pFBC[i] );
            if(pVi && (xattr.visual && pVi->visualid == xattr.visual->visualid) )
            {
                // pick the one with the most samples per pixel
                int nSampleBuf = 0;
                int nSamples = 0;
                glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLE_BUFFERS, &nSampleBuf );
                glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLES       , &nSamples  );

                if ( nBestFBC < 0 || (nSampleBuf && ( nSamples > best_num_samp )) )
                {
                    nBestFBC = i;
                    best_num_samp = nSamples;
                }
            }
            XFree( pVi );
        }

        return pFBC;
    }
}

void X11OpenGLContext::sync()
{
    OpenGLZone aZone;
    glXWaitGL();
    XSync(m_aGLWin.dpy, false);
}

void X11OpenGLContext::swapBuffers()
{
    OpenGLZone aZone;

    glXSwapBuffers(m_aGLWin.dpy, m_aGLWin.win);

    BuffersSwapped();
}

void X11OpenGLContext::resetCurrent()
{
    clearCurrent();

    OpenGLZone aZone;

    if (m_aGLWin.dpy)
    {
        glXMakeCurrent(m_aGLWin.dpy, None, nullptr);
        g_bAnyCurrent = false;
    }
}

bool X11OpenGLContext::isCurrent()
{
    OpenGLZone aZone;
    return g_bAnyCurrent && m_aGLWin.ctx && glXGetCurrentContext() == m_aGLWin.ctx &&
           glXGetCurrentDrawable() == m_aGLWin.win;
}

bool X11OpenGLContext::isAnyCurrent()
{
    return g_bAnyCurrent && glXGetCurrentContext() != None;
}

SystemWindowData X11OpenGLContext::generateWinData(vcl::Window* pParent, bool /*bRequestLegacyContext*/)
{
    OpenGLZone aZone;

    SystemWindowData aWinData;
    aWinData.pVisual = nullptr;
    aWinData.bClipUsingNativeWidget = false;

    const SystemEnvData* sysData(pParent->GetSystemData());

    Display *dpy = static_cast<Display*>(sysData->pDisplay);
    Window win = sysData->GetWindowHandle(pParent->ImplGetFrame());

    if( dpy == nullptr || !glXQueryExtension( dpy, nullptr, nullptr ) )
        return aWinData;

    int best_fbc = -1;
    GLXFBConfig* pFBC = getFBConfig(dpy, win, best_fbc);

    if (!pFBC)
        return aWinData;

    XVisualInfo* vi = nullptr;
    if( best_fbc != -1 )
        vi = glXGetVisualFromFBConfig( dpy, pFBC[best_fbc] );

    XFree(pFBC);

    if( vi )
    {
        VCL_GL_INFO("using VisualID " << vi->visualid);
        aWinData.pVisual = static_cast<void*>(vi->visual);
    }

    return aWinData;
}

bool X11OpenGLContext::ImplInit()
{
    if (!m_aGLWin.dpy)
        return false;

    OpenGLZone aZone;

    GLXContext pSharedCtx( nullptr );
#ifdef DBG_UTIL
    TempErrorHandler aErrorHandler(m_aGLWin.dpy, unxErrorHandler);
#endif

    VCL_GL_INFO("OpenGLContext::ImplInit----start");

    if (!g_vShareList.empty())
        pSharedCtx = g_vShareList.front();

    //tdf#112166 for, e.g. VirtualBox GL, claiming OpenGL 2.1
    static bool hasCreateContextAttribsARB = glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXCreateContextAttribsARB")) != nullptr;
    if (hasCreateContextAttribsARB && !mbRequestLegacyContext)
    {
        int best_fbc = -1;
        GLXFBConfig* pFBC = getFBConfig(m_aGLWin.dpy, m_aGLWin.win, best_fbc);

        if (pFBC && best_fbc != -1)
        {
            int const pContextAttribs[] =
            {
#if 0 // defined(DBG_UTIL)
                GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
                GLX_CONTEXT_MINOR_VERSION_ARB, 2,
#endif
                None

            };
            m_aGLWin.ctx = glXCreateContextAttribsARB(m_aGLWin.dpy, pFBC[best_fbc], pSharedCtx, /* direct, not via X */ GL_TRUE, pContextAttribs);
            SAL_INFO_IF(m_aGLWin.ctx, "vcl.opengl""created a 3.2 core context");
        }
        else
            SAL_WARN("vcl.opengl""unable to find correct FBC");
    }

    if (!m_aGLWin.ctx)
    {
        if (!m_aGLWin.vi)
           return false;

        SAL_WARN("vcl.opengl""attempting to create a non-double-buffered "
                               "visual matching the context");

        m_aGLWin.ctx = glXCreateContext(m_aGLWin.dpy,
                m_aGLWin.vi,
                pSharedCtx,
                GL_TRUE /* direct, not via X server */);
    }

    if( m_aGLWin.ctx )
    {
        g_vShareList.push_back( m_aGLWin.ctx );
    }
    else
    {
        SAL_WARN("vcl.opengl""unable to create GLX context");
        return false;
    }

    if( !glXMakeCurrent( m_aGLWin.dpy, m_aGLWin.win, m_aGLWin.ctx ) )
    {
        g_bAnyCurrent = false;
        SAL_WARN("vcl.opengl""unable to select current GLX context");
        return false;
    }

    g_bAnyCurrent = true;

    int glxMinor, glxMajor;
    double nGLXVersion = 0;
    if( glXQueryVersion( m_aGLWin.dpy, &glxMajor, &glxMinor ) )
      nGLXVersion = glxMajor + 0.1*glxMinor;
    SAL_INFO("vcl.opengl""available GLX version: " << nGLXVersion);

    SAL_INFO("vcl.opengl""available GL extensions: " << glGetString(GL_EXTENSIONS));

    XWindowAttributes aWinAttr;
    if( !XGetWindowAttributes( m_aGLWin.dpy, m_aGLWin.win, &aWinAttr ) )
    {
        SAL_WARN("vcl.opengl""Failed to get window attributes on " << m_aGLWin.win);
        m_aGLWin.Width = 0;
        m_aGLWin.Height = 0;
    }
    else
    {
        m_aGLWin.Width = aWinAttr.width;
        m_aGLWin.Height = aWinAttr.height;
    }

    if( m_aGLWin.HasGLXExtension("GLX_SGI_swap_control" ) )
    {
        // enable vsync
        typedef GLint (*glXSwapIntervalProc)(GLint);
        glXSwapIntervalProc glXSwapInterval = reinterpret_cast<glXSwapIntervalProc>(glXGetProcAddress( reinterpret_cast<const GLubyte*>("glXSwapIntervalSGI") ));
        if( glXSwapInterval )
        {
            TempErrorHandler aLocalErrorHandler(m_aGLWin.dpy, oglErrorHandler);

            errorTriggered = false;

            glXSwapInterval( 1 );

            if( errorTriggered )
                SAL_WARN("vcl.opengl""error when trying to set swap interval, NVIDIA or Mesa bug?");
            else
                VCL_GL_INFO("set swap interval to 1 (enable vsync)");
        }
    }

    bool bRet = InitGL();
    InitGLDebugging();

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    registerAsCurrent();

    return bRet;
}

void X11OpenGLContext::makeCurrent()
{
    if (isCurrent())
        return;

    OpenGLZone aZone;

    clearCurrent();

#ifdef DBG_UTIL
    TempErrorHandler aErrorHandler(m_aGLWin.dpy, unxErrorHandler);
#endif

    if (m_aGLWin.dpy)
    {
        if (!glXMakeCurrent( m_aGLWin.dpy, m_aGLWin.win, m_aGLWin.ctx ))
        {
            g_bAnyCurrent = false;
            SAL_WARN("vcl.opengl""OpenGLContext::makeCurrent failed "
                     "on drawable " << m_aGLWin.win);
            return;
        }
        g_bAnyCurrent = true;
    }

    registerAsCurrent();
}

void X11OpenGLContext::destroyCurrentContext()
{
    if(!m_aGLWin.ctx)
        return;

    std::erase(g_vShareList, m_aGLWin.ctx);

    glXMakeCurrent(m_aGLWin.dpy, None, nullptr);
    g_bAnyCurrent = false;
    if( glGetError() != GL_NO_ERROR )
    {
        SAL_WARN("vcl.opengl""glError: " << glGetError());
    }
    glXDestroyContext(m_aGLWin.dpy, m_aGLWin.ctx);
    m_aGLWin.ctx = nullptr;
}

void X11OpenGLContext::initGLWindow(Visual* pVisual)
{
    OpenGLZone aZone;

    // Get visual info
    {
        XVisualInfo aTemplate;
        aTemplate.visualid = XVisualIDFromVisual( pVisual );
        int nVisuals = 0;
        XVisualInfo* pInfo = XGetVisualInfo( m_aGLWin.dpy, VisualIDMask, &aTemplate, &nVisuals );
        if( nVisuals != 1 )
            SAL_WARN( "vcl.opengl""match count for visual id is not 1" );
        m_aGLWin.vi = pInfo;
    }

    // Check multisample support
    /* TODO: moggi: This is not necessarily correct in the DBG_UTIL path, as it picks
     *      an FBConfig instead ... */

    int nSamples = 0;
    glXGetConfig(m_aGLWin.dpy, m_aGLWin.vi, GLX_SAMPLES, &nSamples);
    if( nSamples > 0 )
        m_aGLWin.bMultiSampleSupported = true;

    m_aGLWin.GLXExtensions = glXQueryExtensionsString( m_aGLWin.dpy, m_aGLWin.screen );
    SAL_INFO("vcl.opengl""available GLX extensions: " << m_aGLWin.GLXExtensions);
}

void X11OpenGLContext::initWindow()
{
    const SystemEnvData* pChildSysData = nullptr;
    SystemWindowData winData = generateWinData(mpWindow, false);
    if( winData.pVisual )
    {
        if( !m_pChildWindow )
        {
            m_pChildWindow = VclPtr<SystemChildWindow>::Create(mpWindow, 0, &winData, false);
        }
        pChildSysData = m_pChildWindow->GetSystemData();
    }

    if (!m_pChildWindow || !pChildSysData)
        return;

    InitChildWindow(m_pChildWindow.get());

    m_aGLWin.dpy = static_cast<Display*>(pChildSysData->pDisplay);
    m_aGLWin.win = pChildSysData->GetWindowHandle(m_pChildWindow->ImplGetFrame());
    m_aGLWin.screen = pChildSysData->nScreen;

    Visual* pVisual = static_cast<Visual*>(pChildSysData->pVisual);
    initGLWindow(pVisual);
}

GLX11Window::GLX11Window()
    : dpy(nullptr)
    , screen(0)
    , win(0)
    , vi(nullptr)
    , ctx(nullptr)
{
}

bool GLX11Window::HasGLXExtension( const char* name ) const
{
    for (sal_Int32 i = 0; i != -1;) {
        if (o3tl::getToken(GLXExtensions, 0, ' ', i) == name) {
            return true;
        }
    }
    return false;
}

GLX11Window::~GLX11Window()
{
    XFree(vi);
}

bool GLX11Window::Synchronize(bool bOnoff) const
{
    XSynchronize(dpy, bOnoff);
    return true;
}

OpenGLContext* X11SalInstance::CreateOpenGLContext()
{
    return new X11OpenGLContext;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=97 H=97 G=96

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© 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.