OPENGL ES3.0 with GLFW on PC

palmer789 wrote on Monday, January 18, 2016:

Hi,
I have meat a problem.
My PC run WIN10 with a NVIDIA card, and I wana develop OPENGL ES 3.0 on it.
After a shot study, I copied the example code and built develop everiment.I use static link to glfw3.lib, libGLESv2.lib and opengl32.lib.I was able to generate exe and run it.
But when I defined GLFW_INCLUDE_ES3 ahead and called glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API), I would get a link error e.g. "TestGLFW.obj : error LNK2019: unresolved external symbol __imp__glCreateShader@4,referenced in function _wmain" .
I think I must have missed some lib, but I don’t know which I missed.
Here is my code:

#include "stdafx.h"
#define  GLFW_INCLUDE_ES3 
#include <glfw3.h>
#include <stdlib.h>
#include <stdio.h>

static void error_callback(int error, const char* description)
{
	fputs(description, stderr);
}

static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}

int _tmain(int argc, _TCHAR* argv[])
{
	GLFWwindow* window;

    glfwSetErrorCallback(error_callback);

    if (!glfwInit())
        exit(EXIT_FAILURE);

	glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API) ;
    window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
	 int result =	glfwGetWindowAttrib(window, GLFW_CLIENT_API) ;

    if (!window)
    {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }

    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);

    glfwSetKeyCallback(window, key_callback);

#ifdef GLFW_INCLUDE_ES3
	glCreateShader(0) ;
#endif

    while (!glfwWindowShouldClose(window))
    {
        float ratio;
        int width, height;

        glfwGetFramebufferSize(window, &width, &height);
        ratio = width / (float) height;

        glViewport(0, 0,  width, height);
		glClear(GL_COLOR_BUFFER_BIT);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwDestroyWindow(window);

    glfwTerminate();
    exit(EXIT_SUCCESS);

	return 0;
}

Thank you for advance.

The powerVR SDK for Windows mentions you need to link against libEGL.lib:

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0668a/CHDEJHDB.html

ANGLE also needs this to be linked to, but doesn’t support 3.0 yet as far as I know.

Since you’re on NVIDIA hardware I think you could also use an extension loader such as GLAD https://github.com/Dav1dde/glad

Note I don’t use OpenGL ES on windows myself, I only know this info second hand.

palmer789 wrote on Tuesday, January 19, 2016:

Hi,
I have searched the link you presented.I got the link error as well after I’ve linked libEGL.lib.Thank you all the same.I will be searhing how to develop Opengl ES 3.0 on my PC and I will post the answer if I could got it. : ).

palmer789 wrote on Tuesday, January 19, 2016:

After I make sure I have used the right lib, libEGL.lib and libGLESv2.lib, I could generate it.It seems like I had linked wrong lib.I will be testing tomorrow to see whether I can run Opengl ES3.0 on my PC. : ).

Glad to hear you’re making progress. If you succeed and get the time to write up the configuration you used that could help future developers.

palmer789 wrote on Wednesday, January 20, 2016:

Yes, I agree with you.I am going to write some test code this evening. : ).

palmer789 wrote on Wednesday, January 20, 2016:

I have met a new problem.
When I called “glCreateShader(GL_VERTEX_SHADER)” after I have called “glfwInit()”, glCreateShader always return 0.
For such issue its even hard to search it.0 0 ~

I’d advise you print the GL_VENDOR, GL_RENDERER and GL_VERSION using glGetString(), and also check the glError() values.

You probably need to set the version you request using glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3) and glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0) as otherwise you may be getting fixed function GL ES 1.x

palmer789 wrote on Thursday, January 21, 2016:

Thanks.
I have spent nearly all day to solve this, but failed. After I called GetString(GL_RENDERER), it returns “ANGLE”.And I have been trying compile the source code to get a right lib. I think I have to create a new thread to describe my problem.I have met a lot problem…It’s really hard to run OPENGL ES using GLFW on PC…

I don’t think you need to open a new thread.

So the GL_RENDERER is ANGLE, but what is the context version? If it’s 1.x then glCreateShader won’t work, you need to initialize the context with the hints I provide above, which the code you’ve given above doesn’t do.

So I would first check your GL_VERSION and set the GLFW_CONTEXT_VERSION_MAJOR and GLFW_CONTEXT_VERSION_MINOR hints as you require (probably 3 and 0).

palmer789 wrote on Thursday, January 21, 2016:

Thank you ~
I have done as you said, called glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3) ;and glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0) , and called glGetString(GL_VERSION ) ;,it throw a exception "Unhandled exception at 0xC0000005 in TestGLFW.exe: 0xC0000005: Access violation reading location 0x00000038"
Had I used a wrong libEGL.lib and libGLESv2.lib?
Thanks for your help. : )

I don’t know what libraries you’re using - did you compile the ANGLE libraries yourself?

An alternative approach to ANGLE is to use the NVIDIA capability to expose OpenGL ES through the standard OpenGL interface. Here you link to OpenGL32.lib (not to libEGL and libGLES), but to get the interface to the OpenGL ES functions you will need an extension loader such as GLAD.

Note: The access violation you’re getting may be because you can’t create a 3.0 GL ES context. So you can try to create a 2.0 one - ANGLE doesn’t fully support 3.0 as yet.

palmer789 wrote on Thursday, January 21, 2016:

Hi,
I don’t know which version libEGL.lib and libGLESv2.lib I used.And I havn’t used libGLES. I have updated my libEGL.lib and libGLESv2.lib just now, then I broke away last exception but my window said I had missed D3DCompiler_43.dll, then I installed D3D9(June 2010) I could run it.
printf("%s\n", glGetString(GL_RENDERER )) ;
printf("%s\n", glGetString(GL_VERSION )) ; Returns
ANGLE
OpenGL ES 2.0 (ANGLE 1.0.0.1318)
and glCreateShader(GL_VERTEX_SHADER) ; Returns 0.
It means glCreateShader failed I think.
But I’ve got a problem that whether I #define GLFW_INCLUDE_ES3 and glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3) ;
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0) ;
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API) ;
the return value are the same.

Additive depend lib are
glfw3dll.lib
libEGL.lib
libGLESv2.lib

And here is my code:

#include "stdafx.h"
#define  GLFW_INCLUDE_ES3 
#define  GLFW_DLL 
#include <glfw3.h>
#include <stdlib.h>
#include <stdio.h>

static void error_callback(int error, const char* description)
{
	fputs(description, stderr);
}

static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}

int _tmain(int argc, _TCHAR* argv[])
{
	GLFWwindow* window;

    glfwSetErrorCallback(error_callback);

    if (!glfwInit())
        exit(EXIT_FAILURE);

#ifdef GLFW_INCLUDE_ES3
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3) ;
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,  0) ;
	glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API) ;
#endif

    window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
	 int result =	glfwGetWindowAttrib(window, GLFW_CLIENT_API) ;

    if (!window)
    {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }

    glfwMakeContextCurrent(window);

	printf("%s\n", glGetString(GL_RENDERER )) ;
	printf("%s\n", glGetString(GL_VERSION )) ;

	int i = glCreateShader(GL_VERTEX_SHADER) ;

	printf ("%d", i) ;

    glfwSwapInterval(1);

    glfwSetKeyCallback(window, key_callback);

    while (!glfwWindowShouldClose(window))
    {
		float ratio;
		int width, height;
		glfwGetFramebufferSize(window, &width, &height);
		ratio = width / (float) height;

		glViewport(0, 0, width, height);
		glClear(GL_COLOR_BUFFER_BIT);

		glfwSwapBuffers(window);
		glfwPollEvents();
    }

    glfwDestroyWindow(window);

    glfwTerminate();
    exit(EXIT_SUCCESS);

	return 0;
}

Best regard!: )

palmer789 wrote on Thursday, January 21, 2016:

I have searched what is ANGLE but I had not got what it is.And I think I need some time to understand that GLAD is.

palmer789 wrote on Thursday, January 21, 2016:

I had learned that NVIDIA card support extension to run OpenGL ES on PC.But what ANGLE is.

palmer789 wrote on Thursday, January 21, 2016:

I am going to go to bed now, I am in GMT+8, best regards, best wishes!

palmer789 wrote on Friday, January 22, 2016:

I have got a new trail.
When I defined GLFE_LIBARIES as opengl32,and then generate the lib and dll, and use it.
After #define GLFW_INCLUDE_ES3 and calle]
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3) ;
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0) ;
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API) ;

Called glGetString(GL_VERSION , it returns OpenGL ES 3.1 NVIDIA 347.52
but glCreateShader(GL_VERTEX_SHADER) retunrs 0 yet.

palmer789 wrote on Saturday, January 23, 2016:

I got it!
I had traveled a long circle for finding the answer.Because of I could not understand it fully, so I will first use a easy way.
Just use the default lib and dll of GLFW, no need to rebuild then use CMake.And use GLEW to get all the GL method through the extension mechanism provied by GLEM.So then if your driver support one method, you can call it through the extension of it.
I will explain more detail after I will have been understanded it.The following is my code, I got it 5 minutes ago.

// Aix3DEdtion.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <GL/glew.h>
#define GLFW_DLL
#define GLFW_INCLUDE_NONE	//	使用GLEW里的头文件
#include <glfw3.h>
#include <stdlib.h>
#include <stdio.h>

GLuint g_programObject ;

GLuint LoadShader ( GLenum type, const char *shaderSrc )
{
	GLuint shader;
	GLint compiled;

	// Create the shader object
	shader = glCreateShader ( type );

	if ( shader == 0 )
	{
		return 0;
	}

	// Load the shader source
	glShaderSource ( shader, 1, &shaderSrc, NULL );

	// Compile the shader
	glCompileShader ( shader );

	// Check the compile status
	glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );

	if ( !compiled )
	{
		GLint infoLen = 0;

		glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );

		if ( infoLen > 1 )
		{
			char *infoLog = (char *)malloc ( sizeof ( char ) * infoLen );

			glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );
			
			free ( infoLog );
		}

		glDeleteShader ( shader );
		return 0;
	}

	return shader;

}

bool Init ()
{
	char vShaderStr[] =
		"#version 300 es                          \n"
		"layout(location = 0) in vec4 vPosition;  \n"
		"void main()                              \n"
		"{                                        \n"
		"   gl_Position = vPosition;              \n"
		"}                                        \n";

	char fShaderStr[] =
		"#version 300 es                              \n"
		"precision mediump float;                     \n"
		"out vec4 fragColor;                          \n"
		"void main()                                  \n"
		"{                                            \n"
		"   fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 );  \n"
		"}                                            \n";

	GLuint vertexShader;
	GLuint fragmentShader;
	GLuint programObject;
	GLint linked;

	// Load the vertex/fragment shaders
	vertexShader = LoadShader ( GL_VERTEX_SHADER, vShaderStr );
	fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, fShaderStr );

	// Create the program object
	programObject = glCreateProgram ( );

	if ( programObject == 0 )
	{
		return 0;
	}

	glAttachShader ( programObject, vertexShader );
	glAttachShader ( programObject, fragmentShader );

	// Link the program
	glLinkProgram ( programObject );

	// Check the link status
	glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );

	if ( !linked )
	{
		GLint infoLen = 0;

		glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen );

		if ( infoLen > 1 )
		{
			char *infoLog = (char *)malloc ( sizeof ( char ) * infoLen );

			glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );
			
			free ( infoLog );
		}

		glDeleteProgram ( programObject );

		return false;
	}

	// Store the program object
	g_programObject = programObject;

	glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f );

	return true;
}

static void error_callback(int error, const char* description)
{
	fputs(description, stderr);
}

static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
		glfwSetWindowShouldClose(window, GL_TRUE);
}

int _tmain(int argc, _TCHAR* argv[])
{
	GLFWwindow* window;

	glfwSetErrorCallback(error_callback);
	if (!glfwInit())
		exit(EXIT_FAILURE);

	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3) ;
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,  0) ;
	glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API) ;

	window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
	int result =	glfwGetWindowAttrib(window, GLFW_CLIENT_API) ;

	if (!window)
	{
		glfwTerminate();
		exit(EXIT_FAILURE);
	}

	glfwMakeContextCurrent(window);
	glfwSwapInterval(1);
	glfwSetKeyCallback(window, key_callback);

	// start GLEW extension handler
	glewExperimental = GL_TRUE;
	glewInit ();

	printf("%s", glGetString(GL_VERSION)) ;

	if (!Init())
		return 0 ;

	while (!glfwWindowShouldClose(window))
	{
		float ratio;
		int width, height;
		glfwGetFramebufferSize(window, &width, &height);
		ratio = width / (float) height;

		GLfloat vVertices[] = {  0.0f,  0.5f, 0.0f,
			-0.5f, -0.5f, 0.0f,
			0.5f, -0.5f, 0.0f
		};

		glViewport ( 0, 0, width, height );

		glClear ( GL_COLOR_BUFFER_BIT );

		// Use the program object
		glUseProgram ( g_programObject );

		// Load the vertex data
		glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );
		glEnableVertexAttribArray ( 0 );

		glDrawArrays ( GL_TRIANGLES, 0, 3 );

		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	glfwDestroyWindow(window);
	glfwTerminate();
	exit(EXIT_SUCCESS);
}

Yes, GLEW should work - it does a similar job as GLAD for extension loading. Happy you managed to get this working!