Приложение MFC, использующее OpenGL для рисования элемента управления, glGetUniformLocation() завершается с ошибкой при втором вызове

Я удалил приведенный ниже код, чтобы попытаться изолировать/проиллюстрировать мою проблему. У меня есть элемент управления MFC Picture CWnd, который я создал для создания собственного элемента управления CGLImage.

Я прекрасно использовал этот метод рисования в немедленном режиме OpenGL. Теперь я пытаюсь использовать шейдерные программы из других моих приложений SDL, и у меня возникают проблемы с доступом к переменным шейдерной программы при втором вызове метода OnPaint().

Я создаю свою программу шейдера один раз при первом вызове OnPaint(). Дескриптор программы по-прежнему действителен при последующих вызовах, но возврат hColor в этой строке всегда равен -1 для последующих вызовов OnPaint():

GLuint hColor = glGetUniformLocation( g_SolidProgram, "vColor4" );

Почему я не могу получить доступ к hColor после первого раза? Конечно, мне не нужно заново создавать программу при каждом вызове OnPaint().

#include "stdafx.h"

#include "MFC_GL.h"
#include "GLImage.h"

#include <glew.h>
#include <gl\glu.h>                             // Header File For The GLu32 Library
#include <freeglut.h>

IMPLEMENT_DYNAMIC(CGLImage, CWnd)

CGLImage::CGLImage()
{

}

CGLImage::~CGLImage()
{
}

#define ID_UPDATE_TIMER 102

BEGIN_MESSAGE_MAP(CGLImage, CWnd)
  ON_WM_PAINT()
  ON_WM_TIMER()
END_MESSAGE_MAP()

int MySetPixelFormat( HDC hdc )
{
    PIXELFORMATDESCRIPTOR pfd = { 
        sizeof(PIXELFORMATDESCRIPTOR),    // size of this pfd 
        1,                                // version number 
        PFD_DRAW_TO_WINDOW |              // support window 
        PFD_SUPPORT_OPENGL |              // support OpenGL 
        PFD_DOUBLEBUFFER,                 // double buffered 
        PFD_TYPE_RGBA,                    // RGBA type 
        24,                               // 24-bit color depth 
        0, 0, 0, 0, 0, 0,                 // color bits ignored 
        0,                                // no alpha buffer 
        0,                                // shift bit ignored 
        0,                                // no accumulation buffer 
        0, 0, 0, 0,                       // accum bits ignored 
        32,                               // 32-bit z-buffer     
        0,                                // no stencil buffer 
        0,                                // no auxiliary buffer 
        PFD_MAIN_PLANE,                   // main layer 
        0,                                // reserved 
        0, 0, 0                           // layer masks ignored 
    }; 
    
    int  iPixelFormat; 
 
    // get the device context's best, available pixel format match 
    if ((iPixelFormat = ChoosePixelFormat(hdc, &pfd)) == 0)
    {
        MessageBox(NULL, "ChoosePixelFormat Failed", NULL, MB_OK);
        return 0;
    }
     
    // make that match the device context's current pixel format 
    if (SetPixelFormat(hdc, iPixelFormat, &pfd) == FALSE)
    {
        MessageBox(NULL, "SetPixelFormat Failed", NULL, MB_OK);
        return 0;
    }

    return 1;
}


#ifndef STRINGIFY
#define STRINGIFY(a) #a
#endif

char *fsSolid  = STRINGIFY(

precision mediump float;
uniform vec4 vColor4;
                           
void main()
{
  gl_FragColor = vColor4;
}
);


char *vsSolid  = STRINGIFY(

attribute vec4 vPosition;

uniform   mat4 MVP;

void main()
{
  gl_Position = MVP * vPosition;
}
);


GLuint BuildShader( char *pszSource, GLenum shaderType )
{
  GLuint hShader = glCreateShader( shaderType );
  glShaderSource( hShader, 1, (char const**) &pszSource, 0 );
  glCompileShader( hShader );
  
  GLint compileSuccess = GL_FALSE;
  
  glGetShaderiv( hShader, GL_COMPILE_STATUS, &compileSuccess );
  
  if ( compileSuccess == GL_FALSE )
  {
    GLchar message[ 256 ];
    glGetShaderInfoLog( hShader, sizeof( message ), 0, &message[ 0 ] );
    printf( "FATAL: SHADER (%s) %s\n", pszSource, message );
    exit( 1 );
  }
  
  return hShader;
}

GLuint BuildProgram( char *pszVertexShaderSource, char *pszFragmentShaderSource )
{
  GLuint vShader = BuildShader( pszVertexShaderSource,   GL_VERTEX_SHADER );
  GLuint fShader = BuildShader( pszFragmentShaderSource, GL_FRAGMENT_SHADER );
  
  GLuint hProgram = glCreateProgram();
  glAttachShader( hProgram, vShader );
  glAttachShader( hProgram, fShader );
  glLinkProgram( hProgram );
  
  GLint linkSuccess;
  
  glGetProgramiv( hProgram, GL_LINK_STATUS, &linkSuccess );
  
  if ( linkSuccess == GL_FALSE )
  {
    GLchar message[ 256 ];
    glGetProgramInfoLog( hProgram, sizeof( message ), 0, &message[ 0 ] );
    printf( "FATAL: %s\n", message );
    exit( 1 );
  }
  
  return hProgram;
}

int g_ScreenWidth  = 320;
int g_ScreenHeight = 200;
GLuint g_SolidProgram;


void CGLImage::OnTimer( UINT_PTR nIDEvent )
{
  switch( nIDEvent )
  {
    case ID_UPDATE_TIMER:
      Invalidate();
      break;
  }
}


void CGLImage::OnPaint()
{
  CPaintDC dc( this ); // device context for painting
  HDC hdc = ::GetDC(m_hWnd);

  MySetPixelFormat( hdc );

  HGLRC hglrc = wglCreateContext( hdc );

  if ( hglrc )
  { 
    // try to make it the thread's current rendering context
    if ( wglMakeCurrent( hdc, hglrc ) )
    {
      static BOOL fFirstTime = TRUE;

      if ( fFirstTime )
      {
        fFirstTime = FALSE;
        //glewExperimental=GL_TRUE;
        GLenum glewRC = glewInit();

        if ( glewRC != GLEW_OK ) {
          printf( "glewInit: %s\n", glewGetErrorString( glewRC ) );
          exit( 1 );
        }

        g_SolidProgram = BuildProgram( vsSolid, fsSolid );

        m_UpdateTimer = ::SetTimer( m_hWnd, ID_UPDATE_TIMER, 100, NULL );
      }

      glUseProgram( g_SolidProgram );
      GLuint hColor = glGetUniformLocation( g_SolidProgram, "vColor4" );  // ### THIS FAILS

      SwapBuffers( hdc );
    } 
  }

  wglMakeCurrent(NULL, NULL) ; 

  ::ReleaseDC (m_hWnd, hdc) ; 
  wglDeleteContext(hglrc); 
}

ОБНОВЛЯТЬ:

Похоже, что вызовы wglCreateContext() и wglMakeCurrent() каким-то образом уничтожают программу шейдера.

  glUseProgram( g_SolidProgram );
  GLuint hColor = glGetUniformLocation( g_SolidProgram, "vColor4" );  // OK HERE

  hglrc = wglCreateContext( hdc );

  if ( wglMakeCurrent( hdc, hglrc ) ) {
    glUseProgram( g_SolidProgram );
    hColor = glGetUniformLocation( g_SolidProgram, "vColor4" );  // BROKEN HERE
  }
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Похоже, что контекст OpenGL может теряться между вызовами OnPaint(). Насколько я помню, MFC может быть требователен к правильности контекста рендеринга. Попробуйте это изменение:

void CGLImage::OnPaint() {
    CPaintDC dc( this ); 
    HDC hdc = ::GetDC(m_hWnd);
    MySetPixelFormat( hdc );
 
    if (!hglrc) { 
        hglrc = wglCreateContext( hdc );
        if ( hglrc ) { 
            wglMakeCurrent( hdc, hglrc ); 
            // Init GLEW (assuming done elsewhere already)
            g_SolidProgram = BuildProgram( vsSolid, fsSolid ); // Build shader once
            m_UpdateTimer = ::SetTimer( m_hWnd, ID_UPDATE_TIMER, 100, NULL ); 
        }
    }

    wglMakeCurrent( hdc, hglrc );

    glUseProgram( g_SolidProgram );
    GLuint hColor = glGetUniformLocation( g_SolidProgram, "vColor4" ); // Should work now 

    // ... rest of ur code
}

Да, мне было интересно просто один раз создать дескрипторы контекста и посмотреть, поможет ли это. Я обновлю в ближайшее время.

SparkyNZ 02.04.2024 00:41

Сохранение контекста внутри переменных-членов и повторное его использование после создания, похоже, помогло.

SparkyNZ 02.04.2024 01:31

Попался, рад, что ты это понял :)

Dylan M. Loszak 02.04.2024 01:35

Другие вопросы по теме