I'm trying to detect a profile of a default OpenGL context created using glfw. This is the way I've implemented it (based on the wiki page)
std::string openGLProfile(){
// Prints the profile of the current context
GLint profile = 0;
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile);
bool core_profile = profile & GL_CONTEXT_CORE_PROFILE_BIT;
bool compatibility_profile = profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
std::string str = "No profile";
if (core_profile == true)
str = "Core profile";
else if (compatibility_profile == true)
str = "Compatibility";
std::cout << str;
}
The problem is that this enumerator GL_CONTEXT_PROFILE_MASK
is apparently not available in some OpenGL versions, like 2.1 and this causes an error.
My question is - how to do the profile check for OpenGL versions that do not have the GL_CONTEXT_PROFILE_MASK? Also, if somebody could point me to the documentation where this profile mask was first introduced, I'd find it very useful. Apparently, the doc for OpenGL 4.xx about glGetIntegerv does not even mention the profile mask, which confuses me.
how to do the profile check for OpenGL versions that do not have the GL_CONTEXT_PROFILE_MASK?
To be precise, OpenGL didn't have notion of profiles until version 3.2, because the most versions before (up to 2.1) were backward compatible. That became a problem when OpenGL 3.0 introduced deprecated functionality and OpenGL 3.1 just removed some functionality from specification. Different vendors, however, kept supporting the backward compatibility via extensions and you had different versions of OpenGL specification existing at the same time. In order to differentiate between them the profiles were introduced, but only in version 3.2.
The most correct answer to your question, is that profiles didn't exist before OpenGL 3.2 and technically there is no profile. However if we boil down this question to how to express profiles dichotomy in older OpenGL versions, then the answer would be as follows:
GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT
, it means 3.0 simulates 3.1 experience, where the backward compatibility is removed and thus it's core profile.GL_ARB_compatibility
is present among extensions string, then all deprecated functions are supported, so it can be treated as compatibility (and core otherwise)GL_CONTEXT_PROFILE_MASK
Actual code would look like this (sorry for the verbose OpenGL version utility functions, but they come handy here)
constexpr GLint GLV(GLint major, GLint minor) {
constexpr auto majorShift = std::numeric_limits<GLint>::digits / 2 - 1;
return (major << majorShift) | minor;
}
GLint glVersion() {
constexpr auto invalid_version = -1;
const auto glVersionString{ reinterpret_cast<const char*>(glGetString(GL_VERSION)) };
GLint major;
const auto majorResult = std::from_chars(glVersionString, glVersionString + 1, major).ec;
if (majorResult == std::errc::invalid_argument) {
return invalid_version;
}
GLint minor;
const auto minorResult = std::from_chars(glVersionString + 2, glVersionString + 3, minor).ec;
if (minorResult == std::errc::invalid_argument) {
return invalid_version;
}
return GLV(major, minor);
}
void reportGLProfile() {
const auto glV = glVersion();
if (glV <= GLV(2, 1)) {
std::cout << "Compatibility profile" << std::endl;
} else if (glV == GLV(3, 0)) {
GLint flags;
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) {
std::cout << "Core profile" << std::endl;
} else {
std::cout << "Compatibility profile" << std::endl;
}
} else if (glV == GLV(3, 1)) {
GLint extensionsNum;
glGetIntegerv(GL_NUM_EXTENSIONS, &extensionsNum);
while (extensionsNum--) {
const auto extensionName = reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, extensionsNum));
if (std::strcmp(extensionName, "GL_ARB_compatibility") == 0) {
std::cout << "Compatibility profile" << std::endl;
return;
}
}
std::cout << "Core profile" << std::endl;
} else {
GLint profile;
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile);
if (const auto errorCode = glGetError()) {
std::cout << "Pending GL error while obtaining profile: " << errorCode << std::endl;
return;
}
if (profile & GL_CONTEXT_CORE_PROFILE_BIT) {
std::cout << "Core profile" << std::endl;
} else {
std::cout << "Compatibility profile" << std::endl;
}
}
}
if somebody could point me to the documentation where this profile mask was first introduced, I'd find it very useful
That is covered by Context Types documentation:
The 3.0 form of context creation did not have the concept of profiles. There was only one form of OpenGL: the core specification. In 3.2, OpenGL was effectively split into two profiles, core and compatibility. An implementation was only required to define core, so compatibility is not guaranteed to be available