Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: [Résolu] Créer un contexte openGL partagé à la main.  (Lu 7289 fois)

0 Membres et 1 Invité sur ce sujet

Canadadry

  • Hero Member
  • *****
  • Messages: 1081
    • Voir le profil
[Résolu] Créer un contexte openGL partagé à la main.
« le: Juillet 16, 2012, 03:57:47 pm »
Bonjour,

Je souhaite avoir une classe de création de context opengl maison. Je me suis fortement inspiré de ta classe Laurent pour ne pas dire que j'ai tout pris. ^^.
Voilà le code de ma classe.
//hpp
#ifndef GLCONTEXT_H
#define GLCONTEXT_H

#include <windows.h>

struct GLContextSettings
{
    explicit GLContextSettings(unsigned int depth = 0, unsigned int stencil = 0, unsigned int antialiasing = 0, unsigned int major = 2, unsigned int minor = 0) :
    DepthBits        (depth),
    StencilBits      (stencil),
    AntialiasingLevel(antialiasing),
    MajorVersion     (major),
    MinorVersion     (minor)
    {
    }
    unsigned int DepthBits;
    unsigned int StencilBits;
    unsigned int AntialiasingLevel;
    unsigned int MajorVersion;
    unsigned int MinorVersion;
};

class GLContext
{
public:
    GLContext(GLContext* shared, const GLContextSettings& settings);
    virtual ~GLContext();
    const GLContextSettings& getSettings() const;
    bool isValid() const;
    bool MakeCurrent();

    static GLContext* getCurrentGLContext();


private:
    GLContext();
    void createContext(GLContext* shared, unsigned int bitsPerPixel, const GLContextSettings& settings);
    static int EvaluateFormat(unsigned int bitsPerPixel, const GLContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing);

    static GLContext* m_staticCurrentContext;
    HWND              m_window;
    HDC               m_deviceContext;
    HGLRC             m_context;
    GLContextSettings m_settings;
};

#endif // GLCONTEXT_H

#include "glcontext.h"

#include <windows.h>
#include <GL/gl.h>

#include "glext/wglext.h"
#include <cstdio>
#include <cmath>

#define ABS(x) ((x)>0)?(x):(-(x))

GLContext* GLContext::m_staticCurrentContext = NULL;

GLContext::GLContext()
: m_window(NULL)
, m_deviceContext(NULL)
, m_context(NULL)
, m_settings()
{
}

GLContext::GLContext(GLContext* shared, const GLContextSettings& settings)
: m_window(NULL)
, m_deviceContext(NULL)
, m_context(NULL)
, m_settings()
{

    // if constext isn't valid we create a dummy window
    if(shared != NULL)
    {
        m_deviceContext = shared->m_deviceContext;
    }
    if(m_deviceContext == NULL)
    {
        // Creating a dummy window is mandatory: we could create a memory DC but then
        // its pixel format wouldn't match the regular contexts' format, and thus
        // wglShareLists would always fail. Too bad...
        m_window = CreateWindowA("STATIC", "", WS_POPUP | WS_DISABLED, 0, 0, 1, 1, NULL, NULL, GetModuleHandle(NULL), NULL);
        ShowWindow(m_window, SW_HIDE);
        m_deviceContext = GetDC(m_window);
    }
// Create the context
    if (m_deviceContext)
        createContext(shared,32,settings);
}

GLContext::~GLContext()
{
    if (m_context)
    {
        if (wglGetCurrentContext() == m_context) wglMakeCurrent(NULL, NULL);
        wglDeleteContext(m_context);
    }

    // if we own a window we also own his DC
    if (m_window)
    {
        ReleaseDC(m_window, m_deviceContext);
        DestroyWindow(m_window);
    }
}

bool GLContext::MakeCurrent()
{
     return m_deviceContext && m_context && wglMakeCurrent(m_deviceContext, m_context);
}

const GLContextSettings& GLContext::getSettings() const
{
    return m_settings;
}

bool GLContext::isValid() const
{
    return (m_deviceContext != NULL) && (m_context != NULL);
}

GLContext* GLContext::getCurrentGLContext()
{
    if(m_staticCurrentContext == NULL) m_staticCurrentContext = new GLContext();


    PIXELFORMATDESCRIPTOR  descriptor;

    int  iPixelFormat = GetPixelFormat(m_staticCurrentContext->m_deviceContext );
    DescribePixelFormat(m_staticCurrentContext->m_deviceContext, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &descriptor);
    m_staticCurrentContext->m_deviceContext              = wglGetCurrentDC();
    m_staticCurrentContext->m_context                    = wglGetCurrentContext();
    m_staticCurrentContext->m_settings.DepthBits         = descriptor.cDepthBits;
    m_staticCurrentContext->m_settings.StencilBits       = descriptor.cStencilBits;
    // TODO : use wglgetpixelformatattribivarb to retreive antialiasing level
    m_staticCurrentContext->m_settings.AntialiasingLevel = 0;
    // TODO : look at wglCreateContextAttribsARB to retreive openGL version
    m_staticCurrentContext->m_settings.MajorVersion      = 2;
    m_staticCurrentContext->m_settings.MinorVersion      = 0;

    return m_staticCurrentContext;
}

void GLContext::createContext(GLContext* shared, unsigned int bitsPerPixel, const GLContextSettings& settings)
{

    // Save the creation settings
    m_settings = settings;

    // Let's find a suitable pixel format -- first try with antialiasing
    int bestFormat = 0;
    if (m_settings.AntialiasingLevel > 0)
    {
        // Get the wglChoosePixelFormatARB function (it is an extension)
        PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = reinterpret_cast<PFNWGLCHOOSEPIXELFORMATARBPROC>(wglGetProcAddress("wglChoosePixelFormatARB"));
        if (wglChoosePixelFormatARB)
        {
            // Define the basic attributes we want for our window
            int intAttributes[] =
            {
                WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
                        WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
                        WGL_ACCELERATION_ARB,   WGL_FULL_ACCELERATION_ARB,
                        WGL_DOUBLE_BUFFER_ARB,  GL_TRUE,
                WGL_SAMPLE_BUFFERS_ARB, (m_settings.AntialiasingLevel ? GL_TRUE : GL_FALSE),
                        WGL_SAMPLES_ARB,        m_settings.AntialiasingLevel,
                        0,                      0
            };

            // Let's check how many formats are supporting our requirements
            int   formats[128];
                UINT  nbFormats;
                float floatAttributes[] = {0, 0};
                bool  isValid = wglChoosePixelFormatARB(m_deviceContext, intAttributes, floatAttributes, sizeof(formats) / sizeof(*formats), formats, &nbFormats) != 0;
            while ((!isValid || (nbFormats == 0)) && m_settings.AntialiasingLevel > 0)
            {
                // Decrease the antialiasing level until we find a valid one
                m_settings.AntialiasingLevel--;
                intAttributes[11] = m_settings.AntialiasingLevel;
                isValid = wglChoosePixelFormatARB(m_deviceContext, intAttributes, floatAttributes, sizeof(formats) / sizeof(*formats), formats, &nbFormats) != 0;
            }

            // Get the best format among the returned ones
            if (isValid && (nbFormats > 0))
            {
                int bestScore = 0xFFFF;
                for (UINT i = 0; i < nbFormats; ++i)
                {
                    // Get the current format's attributes
                    PIXELFORMATDESCRIPTOR attributes;
                    attributes.nSize    = sizeof(attributes);
                    attributes.nVersion = 1;
                    DescribePixelFormat(m_deviceContext, formats[i], sizeof(attributes), &attributes);

                    // Evaluate the current configuration
                    int color = attributes.cRedBits + attributes.cGreenBits + attributes.cBlueBits + attributes.cAlphaBits;
                    int score = EvaluateFormat(bitsPerPixel, m_settings, color, attributes.cDepthBits, attributes.cStencilBits, m_settings.AntialiasingLevel);

                    // Keep it if it's better than the current best
                    if (score < bestScore)
                    {
                        bestScore  = score;
                        bestFormat = formats[i];
                    }
                }
            }
        }
        else
        {
            // wglChoosePixelFormatARB not supported ; disabling antialiasing
            printf("Antialiasing is not supported ; it will be disabled\n");
            m_settings.AntialiasingLevel = 0;
        }
    }

    // Find a pixel format with no antialiasing, if not needed or not supported
    if (bestFormat == 0)
    {
        // Setup a pixel format descriptor from the rendering settings
        PIXELFORMATDESCRIPTOR descriptor;
        ZeroMemory(&descriptor, sizeof(descriptor));
        descriptor.nSize        = sizeof(descriptor);
        descriptor.nVersion     = 1;
        descriptor.iLayerType   = PFD_MAIN_PLANE;
        descriptor.dwFlags      = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
        descriptor.iPixelType   = PFD_TYPE_RGBA;
        descriptor.cColorBits   = static_cast<BYTE>(bitsPerPixel);
        descriptor.cDepthBits   = static_cast<BYTE>(m_settings.DepthBits);
        descriptor.cStencilBits = static_cast<BYTE>(m_settings.StencilBits);
        descriptor.cAlphaBits   = bitsPerPixel == 32 ? 8 : 0;

        // Get the pixel format that best matches our requirements
        bestFormat = ChoosePixelFormat(m_deviceContext, &descriptor);
        if (bestFormat == 0)
        {
            printf("Failed to find a suitable pixel format for device context -- cannot create OpenGL context\n");
            return;
        }
    }

    // Extract the depth and stencil bits from the chosen format
    PIXELFORMATDESCRIPTOR actualFormat;
    actualFormat.nSize    = sizeof(actualFormat);
    actualFormat.nVersion = 1;
    DescribePixelFormat(m_deviceContext, bestFormat, sizeof(actualFormat), &actualFormat);
    m_settings.DepthBits   = actualFormat.cDepthBits;
    m_settings.StencilBits = actualFormat.cStencilBits;

    // Set the chosen pixel format
    if (!SetPixelFormat(m_deviceContext, bestFormat, &actualFormat))
    {
        printf("Failed to set pixel format for device context -- cannot create OpenGL context\n");
        return;
    }

    // Get the context to share display lists with
    HGLRC sharedContext = shared ? shared->m_context : NULL;

    // Create the OpenGL context -- first try context versions >= 3.0 if it is requested (they require special code)
    while (!m_context && (m_settings.MajorVersion >= 3))
    {
        PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = reinterpret_cast<PFNWGLCREATECONTEXTATTRIBSARBPROC>(wglGetProcAddress("wglCreateContextAttribsARB"));
        if (wglCreateContextAttribsARB)
        {
            int attributes[] =
            {
                WGL_CONTEXT_MAJOR_VERSION_ARB, m_settings.MajorVersion,
                WGL_CONTEXT_MINOR_VERSION_ARB, m_settings.MinorVersion,
                WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
                0, 0
            };
            m_context = wglCreateContextAttribsARB(m_deviceContext, sharedContext, attributes);
        }

        // If we couldn't create the context, lower the version number and try again -- stop at 3.0
        // Invalid version numbers will be generated by this algorithm (like 3.9), but we really don't care
        if (!m_context)
        {
            if (m_settings.MinorVersion > 0)
            {
                // If the minor version is not 0, we decrease it and try again
                m_settings.MinorVersion--;
            }
            else
            {
                // If the minor version is 0, we decrease the major version
                m_settings.MajorVersion--;
                m_settings.MinorVersion = 9;
            }
        }
    }

    // If the OpenGL >= 3.0 context failed or if we don't want one, create a regular OpenGL 1.x/2.x context
    if (!m_context)
    {
        // set the context version to 2.0 (arbitrary)
        m_settings.MajorVersion = 2;
        m_settings.MinorVersion = 0;

        m_context = wglCreateContext(m_deviceContext);
        if (!m_context)
        {
            printf("Failed to create an OpenGL context for this window\n");
            return;
        }

        // Share this context with others
        if (sharedContext)
        {
            // WARNING : wglShareLists doesn't seem to be thread-saf
            if (!wglShareLists(sharedContext, m_context))
                printf("Failed to share the OpenGL context\n");
        }
    }
}

int GLContext::EvaluateFormat(unsigned int bitsPerPixel, const GLContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing)
{
    return ABS(static_cast<int>(bitsPerPixel               - colorBits))   +
           ABS(static_cast<int>(settings.DepthBits         - depthBits))   +
           ABS(static_cast<int>(settings.StencilBits       - stencilBits)) +
           ABS(static_cast<int>(settings.AntialiasingLevel - antialiasing));
}

//cpp
 

J'arrive à créer des contextes depuis rien, à en partager, mais si j'essaie d'en créer un partagé avec un fenetre SFML j'ai une erreur lors du SetPixelFormat.  Je test avec ce code :
int main(int argc, char** argv)
{
    sf::RenderWindow App(sf::VideoMode(800, 600), "DEMO_MDE");
    //GLContext context(NULL,GLContextSettings());
    GLContext context2(GLContext::getCurrentGLContext(),GLContextSettings());
    printf("active other context : %d\n",context.MakeCurrent());
    printf("active other context : %d\n",context2.MakeCurrent());
}
 

Mais si je décommente la ligne deux et que je commente la première je n'ai plus d'erreur.  Je ne comprends pas vraiment ce qu'il se passe. Si quelqu'un avait une idée.

Merci d'avance.
« Modifié: Juillet 18, 2012, 02:03:38 pm par Canadadry »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Créer un contexte openGL partagé à la main.
« Réponse #1 le: Juillet 16, 2012, 04:37:36 pm »
Pour que deux contextes puissent être partagés, il faut qu'ils aient un certain nombre d'attributs identiques. En l'occurence le format de pixel.

Mais du coup ça devrait générer une erreur lors de l'appel à wglShareLists, pas SetPixelFormat (puisqu'à ce moment-là, le contexte ne sait pas qu'il va être partagé). Donc c'est peut-être autre chose.

Tu n'as pas plus de précisions sur l'erreur (message, code) ?
Laurent Gomila - SFML developer

Canadadry

  • Hero Member
  • *****
  • Messages: 1081
    • Voir le profil
Re : Créer un contexte openGL partagé à la main.
« Réponse #2 le: Juillet 16, 2012, 07:56:55 pm »
Oui mais le SetPixelFormat n'est pas lié au DC ?  vu que tu l'appel avant de créer le contexte. Comment pourrais-je avoir deux contextes différent (non partagé) lié au même DC si l'appel au SetPixelFormat s'applique au DC ?

Non pour le moment je sais juste que le SetPixelFormat me renvoie faux vu que je vois le printf associé à l'erreur. ("Failed to set pixel format for device context -- cannot create OpenGL context")       

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Créer un contexte openGL partagé à la main.
« Réponse #3 le: Juillet 16, 2012, 08:56:30 pm »
Il faudrait récupérer l'erreur (GetLastError) et afficher un beau message d'erreur (FormatMessage).
Laurent Gomila - SFML developer

Canadadry

  • Hero Member
  • *****
  • Messages: 1081
    • Voir le profil
Re : Créer un contexte openGL partagé à la main.
« Réponse #4 le: Juillet 17, 2012, 09:06:23 am »
Il me dit que le format de pixel n'est pas valide...

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Créer un contexte openGL partagé à la main.
« Réponse #5 le: Juillet 17, 2012, 09:20:18 am »
int  iPixelFormat = GetPixelFormat(m_staticCurrentContext->m_deviceContext );
DescribePixelFormat(m_staticCurrentContext->m_deviceContext, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &descriptor);
m_staticCurrentContext->m_deviceContext              = wglGetCurrentDC();
C'est normal que tu récupères le détail du pixel format du HDC avant d'avoir le HDC ?
Laurent Gomila - SFML developer

Canadadry

  • Hero Member
  • *****
  • Messages: 1081
    • Voir le profil
Re : Créer un contexte openGL partagé à la main.
« Réponse #6 le: Juillet 17, 2012, 09:40:36 am »
Non en effet, mais ça ne change rien, et je pense que je ne vais pas trop gratter pour voir pourquoi ça ne passe pas. Sachant qu'on est sur que ça ne pourra pas passer le wglShareLists.

Au passage, tu peux m'expliquer pourquoi je peux avoir deux contextes non partagé lié au même DC avec des formats de pixel différent si l'appel au SetPixelFormat s'applique au DC ?

Merci pour ton aide.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Créer un contexte openGL partagé à la main.
« Réponse #7 le: Juillet 17, 2012, 09:49:49 am »
Citer
Au passage, tu peux m'expliquer pourquoi je peux avoir deux contextes non partagé lié au même DC avec des formats de pixel différent si l'appel au SetPixelFormat s'applique au DC ?
Peux-tu montrer le code qui fait ça ?
Laurent Gomila - SFML developer

Canadadry

  • Hero Member
  • *****
  • Messages: 1081
    • Voir le profil
Re : Créer un contexte openGL partagé à la main.
« Réponse #8 le: Juillet 17, 2012, 11:44:06 am »
J'utilise ta fonction de création de context.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Créer un contexte openGL partagé à la main.
« Réponse #9 le: Juillet 17, 2012, 11:50:55 am »
Je parlais surtout du main() qui produit ce cas de figure ;)
Laurent Gomila - SFML developer

Canadadry

  • Hero Member
  • *****
  • Messages: 1081
    • Voir le profil
Re : Créer un contexte openGL partagé à la main.
« Réponse #10 le: Juillet 17, 2012, 04:30:10 pm »
Voilà la dernière version.


void HandleLastError(const char *msg /* = "Error occured" */) {
        DWORD errCode = GetLastError();
        char *err;
        if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                           NULL,
                           errCode,
                           MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
                           (LPTSTR) &err,
                           0,
                           NULL))
            return;

        printf( "ERROR: %s: %s\n", msg, err);
        LocalFree(err);
}

int main(int argc, char** argv)
{
    sf::RenderWindow App(sf::VideoMode(800, 600), "DEMO_MDE");
    //GLContext context(NULL,GLContextSettings());
    GLContext context2(GLContext::getCurrentGLContext(),GLContextSettings());
    if(!context2.MakeCurrent()) HandleLastError("contextCreation") ;
    printf("active other context : %d\n",context.MakeCurrent());
    printf("active other context : %d\n",context2.MakeCurrent());
}
 
« Modifié: Juillet 17, 2012, 04:34:08 pm par Canadadry »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Créer un contexte openGL partagé à la main.
« Réponse #11 le: Juillet 17, 2012, 05:00:09 pm »
Mais ça, ça ne marche pas ?
Laurent Gomila - SFML developer

Canadadry

  • Hero Member
  • *****
  • Messages: 1081
    • Voir le profil
Re : Créer un contexte openGL partagé à la main.
« Réponse #12 le: Juillet 17, 2012, 05:13:47 pm »
Non ça bloque au setpixelformat.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Créer un contexte openGL partagé à la main.
« Réponse #13 le: Juillet 17, 2012, 08:57:50 pm »
Alors j'ai mal compris ta question.

Citer
Au passage, tu peux m'expliquer pourquoi je peux avoir deux contextes non partagé lié au même DC avec des formats de pixel différent si l'appel au SetPixelFormat s'applique au DC ?
Laurent Gomila - SFML developer

Canadadry

  • Hero Member
  • *****
  • Messages: 1081
    • Voir le profil
Re : Re : Créer un contexte openGL partagé à la main.
« Réponse #14 le: Juillet 17, 2012, 11:37:13 pm »
Mais du coup ça devrait générer une erreur lors de l'appel à wglShareLists, pas SetPixelFormat (puisqu'à ce moment-là, le contexte ne sait pas qu'il va être partagé). Donc c'est peut-être autre chose.

Je fais référence à ça. Néanmoins ce code ne provoque pas d'erreur mes deux contextes sont crée

int main(int argc, char** argv)
{
    //sf::RenderWindow App(sf::VideoMode(800, 600), "DEMO_MDE");
    GLContext context(NULL,GLContextSettings(16,8));
    GLContext context2(GLContext::getCurrentGLContext(),GLContextSettings(8,16));
    if(!context2.MakeCurrent()) HandleLastError("contextCreation") ;
    printf("active other context : %d\n",context.MakeCurrent());
    printf("active other context : %d\n",context2.MakeCurrent());
}
 

Pourtant les format de pixel sont à mon sens clairement différent.... Encore que je n'ai pas vérifié le retour ChoosePixelFormat.
« Modifié: Juillet 17, 2012, 11:38:53 pm par Canadadry »

 

anything