03-25-2019, 03:39 PM
(This post was last modified: 02-14-2020, 11:56 AM by Brian Beuken.)
I generally don't use many extensions, but now that we're getting into OpenGLES3.0 its important to make use of them, and they can be confusing.
I just tried to use some on Raspberry and discovered some interesting issues, namely a missing lib called libdl which needs to be added if you are going to use extensions on a current Raspberry. Not sure about other boards as I don't have one set up, but if you get a link error add dl
Using an extension requires that you set it up first and that is the first minefield, you can of course list the extensions your system supports using somethng like
printf("This GPU supports these extensions :%s\n", glGetString(GL_EXTENSIONS));
Which will give you a nice list of "extensions" for a Raspberry like this.
This GPU supports these extensions :GL_OES_compressed_ETC1_RGB8_texture GL_OES_compressed_paletted_texture GL_OES_texture_npot GL_OES_depth24 GL_OES_vertex_half_float GL_OES_EGL_image GL_OES_EGL_image_external GL_EXT_discard_framebuffer GL_OES_rgb8_rgba8 GL_OES_depth32 GL_OES_mapbuffer GL_EXT_texture_format_BGRA8888 GL_APPLE_rgb_422 GL_EXT_debug_marker
I put "extensions" in quotes becuase these are not the names of the functions but rather a grouping for the extensions actually available.
This is a mix, some of these extensions are types, and some are functions. The types we don't care too much about just adding #include <GLES2/gl2ext.h> will give us access to the types that are associated with that name....for example "extension" GL_OES_rgb8_rgba8
Gives us, 2 new defines that are associated with calls that set up RGBA. We can define types just by adding the GL2Ext.h file.
You may have to define the type in your pre-processor but I've not noticed it. It tends to set them all up these days, so be sure you use them in the correct functions.
Functions are a bit harder. Depending on your system and the current version of the drivers it has, you have to interrogate the system to get the addresses of the functions, and you also have to create alias values for them.
The Raspberry does not have a lot of extension functions but lets look at one as an example
GL_OES_mapbuffer
If we look in the GL2ext.h file for this we find
Which is a bit confusing.. but what that extension is telling us is that there are 3 functions that relate to it, called. glMapBufferOES glUnmapBufferOES and glGetBufferPointervOES
What we want to do now is create 3 alias functions, called glMapBuffer glUnmapBuffer and glGetBufferPointerv
We can leave the OES if we want but tradition states we remove it, Now notice the typedef, and you can also see that the 3 functions return very different types. void*, GLboolean and void.
and there is somehing called a PFNLGL XXXXXXX PROC where XXXXXXX is replaced by the name of the function..(in caps) That will internally define what the signature of the function is going to be and ensure we get the right result back from the function. As well as setting up what values are passed.
This is a clunky system but it is how we can create a function and send and receive the expected values.
We need to define our function in an accessable space, I tend to use my graphic class since graphics are most likely to use extensions So if you need to use these outside of graphic routines, make sure you can access the class.
PFNGLMAPBUFFEROESPROC glMapBuffer = NULL;
So we've made that..now we have to load it with the address of the function...which is something EGL does for us with a standard function Again set this up in the graphic class init.
glMapBuffer = (PFNGLMAPBUFFEROESPROC)eglGetProcAddress("glMapBufferOES");
And now glMapBuffer is available
eglGetProcAddress asks the OpenGLES2 libs if it has a function called glMapBufferOES and of course it has. (it will return null otherwise) So now we can use glMapBuffer as a function like this.
unsigned char* framedata = (unsigned char*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
Now the function can work as if it is a standard gl function, and GL_WRITE_ONLY_OES is activated as part of its types it needs.
(now, there does seem to be a few issues with mapbuffer on raspberry, but this example still stands on how to make and use an extension)
Each extension has its own PFNGLXXXXXXXPROC make sure you define your alias with that specific typedef and though you can use any name at all, keeping the name of the function with or without the makers value is a good plan to keep it readable.
There a good explanation here https://community.nxp.com/docs/DOC-101502
If you are going to use extensions, then it means you can only be certain that your code may only run on the same systems you build it on. That means you need to be careful if running on a similar, or older, or ever newer machine to check that the extension is available, if not you need to either not use that function, or use a different method. Never assume that becuase a Raspberry has a function, that an Odroid or a Nano Pi also has it.. Make sure when you use an extension to provide an alternative. Preferably not a crash
Here's some useful info on extension being available. though this is for windows so uses wgl not egl and talk of nvidia is a bit optomistic for SBC's
I just tried to use some on Raspberry and discovered some interesting issues, namely a missing lib called libdl which needs to be added if you are going to use extensions on a current Raspberry. Not sure about other boards as I don't have one set up, but if you get a link error add dl
Using an extension requires that you set it up first and that is the first minefield, you can of course list the extensions your system supports using somethng like
printf("This GPU supports these extensions :%s\n", glGetString(GL_EXTENSIONS));
Which will give you a nice list of "extensions" for a Raspberry like this.
This GPU supports these extensions :GL_OES_compressed_ETC1_RGB8_texture GL_OES_compressed_paletted_texture GL_OES_texture_npot GL_OES_depth24 GL_OES_vertex_half_float GL_OES_EGL_image GL_OES_EGL_image_external GL_EXT_discard_framebuffer GL_OES_rgb8_rgba8 GL_OES_depth32 GL_OES_mapbuffer GL_EXT_texture_format_BGRA8888 GL_APPLE_rgb_422 GL_EXT_debug_marker
I put "extensions" in quotes becuase these are not the names of the functions but rather a grouping for the extensions actually available.
This is a mix, some of these extensions are types, and some are functions. The types we don't care too much about just adding #include <GLES2/gl2ext.h> will give us access to the types that are associated with that name....for example "extension" GL_OES_rgb8_rgba8
Code:
* GL_OES_rgb8_rgba8 */
#ifndef GL_OES_rgb8_rgba8
#define GL_RGB8_OES 0x8051
#define GL_RGBA8_OES 0x8058
#endif
Gives us, 2 new defines that are associated with calls that set up RGBA. We can define types just by adding the GL2Ext.h file.
You may have to define the type in your pre-processor but I've not noticed it. It tends to set them all up these days, so be sure you use them in the correct functions.
Functions are a bit harder. Depending on your system and the current version of the drivers it has, you have to interrogate the system to get the addresses of the functions, and you also have to create alias values for them.
The Raspberry does not have a lot of extension functions but lets look at one as an example
GL_OES_mapbuffer
If we look in the GL2ext.h file for this we find
Code:
/* GL_OES_mapbuffer */
#ifndef GL_OES_mapbuffer
#define GL_OES_mapbuffer 0
#ifdef GL_GLEXT_PROTOTYPES
GL_APICALL void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);
GL_APICALL GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target);
GL_APICALL void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, GLvoid** params);
#endif
typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target);
typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, GLvoid** params);
#endif
Which is a bit confusing.. but what that extension is telling us is that there are 3 functions that relate to it, called. glMapBufferOES glUnmapBufferOES and glGetBufferPointervOES
What we want to do now is create 3 alias functions, called glMapBuffer glUnmapBuffer and glGetBufferPointerv
We can leave the OES if we want but tradition states we remove it, Now notice the typedef, and you can also see that the 3 functions return very different types. void*, GLboolean and void.
and there is somehing called a PFNLGL XXXXXXX PROC where XXXXXXX is replaced by the name of the function..(in caps) That will internally define what the signature of the function is going to be and ensure we get the right result back from the function. As well as setting up what values are passed.
This is a clunky system but it is how we can create a function and send and receive the expected values.
We need to define our function in an accessable space, I tend to use my graphic class since graphics are most likely to use extensions So if you need to use these outside of graphic routines, make sure you can access the class.
PFNGLMAPBUFFEROESPROC glMapBuffer = NULL;
So we've made that..now we have to load it with the address of the function...which is something EGL does for us with a standard function Again set this up in the graphic class init.
glMapBuffer = (PFNGLMAPBUFFEROESPROC)eglGetProcAddress("glMapBufferOES");
And now glMapBuffer is available
eglGetProcAddress asks the OpenGLES2 libs if it has a function called glMapBufferOES and of course it has. (it will return null otherwise) So now we can use glMapBuffer as a function like this.
unsigned char* framedata = (unsigned char*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
Now the function can work as if it is a standard gl function, and GL_WRITE_ONLY_OES is activated as part of its types it needs.
(now, there does seem to be a few issues with mapbuffer on raspberry, but this example still stands on how to make and use an extension)
Each extension has its own PFNGLXXXXXXXPROC make sure you define your alias with that specific typedef and though you can use any name at all, keeping the name of the function with or without the makers value is a good plan to keep it readable.
There a good explanation here https://community.nxp.com/docs/DOC-101502
If you are going to use extensions, then it means you can only be certain that your code may only run on the same systems you build it on. That means you need to be careful if running on a similar, or older, or ever newer machine to check that the extension is available, if not you need to either not use that function, or use a different method. Never assume that becuase a Raspberry has a function, that an Odroid or a Nano Pi also has it.. Make sure when you use an extension to provide an alternative. Preferably not a crash
Here's some useful info on extension being available. though this is for windows so uses wgl not egl and talk of nvidia is a bit optomistic for SBC's
Brian Beuken
Lecturer in Game Programming at Breda University of Applied Sciences.
Author of The Fundamentals of C/C++ Game Programming: Using Target-based Development on SBC's
Lecturer in Game Programming at Breda University of Applied Sciences.
Author of The Fundamentals of C/C++ Game Programming: Using Target-based Development on SBC's