MFC 应用程序使用 OpenGL 绘制控件,glGetUniformLocation() 在第二次调用时失败

问题描述 投票:0回答:1

我已经删除了下面的代码来尝试隔离/说明我的问题。我有一个 MFC Picture CWnd 控件,我派生该控件来创建我自己的 CGLImage 控件。

我已经使用这种方法在 OpenGL 即时模式下绘制得很好。现在,我尝试使用其他 SDL 应用程序中的着色器程序,但在第二次调用 OnPaint() 方法时访问着色器程序变量时遇到问题。

我在第一次 OnPaint() 调用时创建一次着色器程序。程序句柄在后续调用中仍然有效,但对于后续 OnPaint() 调用,此行中的 hColor 返回始终为 -1:

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
  }
windows opengl mfc shader opengl-3
1个回答
0
投票

看起来 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

}

© www.soinside.com 2019 - 2024. All rights reserved.