Я удалил приведенный ниже код, чтобы попытаться изолировать/проиллюстрировать мою проблему. У меня есть элемент управления 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
}
Похоже, что контекст 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
}
Сохранение контекста внутри переменных-членов и повторное его использование после создания, похоже, помогло.
Попался, рад, что ты это понял :)
Да, мне было интересно просто один раз создать дескрипторы контекста и посмотреть, поможет ли это. Я обновлю в ближайшее время.