Skip to content

Commit

Permalink
Make EGL pixel format selection follow the same procedure as the othe…
Browse files Browse the repository at this point in the history
…r context types and make OpenGL context version parsing more tolerant of garbage data. Fixes SFML#2395
  • Loading branch information
intjelic authored and ChrisThrasher committed Apr 4, 2023
1 parent 7004db1 commit 6a3feda
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 69 deletions.
12 changes: 8 additions & 4 deletions src/SFML/Graphics/RenderTextureImplFBO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,15 +263,17 @@ bool RenderTextureImplFBO::create(const Vector2u& size, unsigned int textureId,
static_cast<GLsizei>(size.x),
static_cast<GLsizei>(size.y)));

m_stencil = true;

#else

m_stencil = false;

err() << "Impossible to create render texture (failed to create the attached depth/stencil buffer)"
<< std::endl;
return false;

#endif // SFML_OPENGL_ES

m_stencil = true;
}
else if (settings.depthBits)
{
Expand Down Expand Up @@ -355,14 +357,16 @@ bool RenderTextureImplFBO::create(const Vector2u& size, unsigned int textureId,
static_cast<GLsizei>(size.y)));
}

m_multisample = true;

#else

m_multisample = false;

err() << "Impossible to create render texture (failed to create the multisample render buffers)" << std::endl;
return false;

#endif // SFML_OPENGL_ES

m_multisample = true;
}
}

Expand Down
149 changes: 96 additions & 53 deletions src/SFML/Window/EglContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <SFML/Window/EglContext.hpp>
#include <SFML/Window/WindowImpl.hpp>

#include <memory>
#include <mutex>
#include <ostream>
#ifdef SFML_SYSTEM_ANDROID
Expand Down Expand Up @@ -80,18 +81,27 @@ EGLDisplay getInitializedDisplay()
////////////////////////////////////////////////////////////
void ensureInit()
{
static bool initialized = false;
if (!initialized)
{
initialized = true;
static std::once_flag flag;

// We don't check the return value since the extension
// flags are cleared even if loading fails
gladLoaderLoadEGL(EGL_NO_DISPLAY);
std::call_once(flag,
[]()
{
if (!gladLoaderLoadEGL(EGL_NO_DISPLAY))
{
// At this point, the failure is unrecoverable
// Dump a message to the console and let the application terminate
sf::err() << "Failed to load EGL entry points" << std::endl;

// Continue loading with a display
gladLoaderLoadEGL(getInitializedDisplay());
}
assert(false);

return false;
}

// Continue loading with a display
gladLoaderLoadEGL(getInitializedDisplay());

return true;
});
}
} // namespace EglContextImpl
} // namespace
Expand Down Expand Up @@ -287,67 +297,100 @@ EGLConfig EglContext::getBestConfig(EGLDisplay display, unsigned int bitsPerPixe
{
EglContextImpl::ensureInit();

// Set our video settings constraint
const EGLint attributes[] =
{EGL_BUFFER_SIZE,
static_cast<EGLint>(bitsPerPixel),
EGL_DEPTH_SIZE,
static_cast<EGLint>(settings.depthBits),
EGL_STENCIL_SIZE,
static_cast<EGLint>(settings.stencilBits),
EGL_SAMPLE_BUFFERS,
settings.antialiasingLevel ? 1 : 0,
EGL_SAMPLES,
static_cast<EGLint>(settings.antialiasingLevel),
EGL_SURFACE_TYPE,
EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE,
EGL_OPENGL_ES_BIT,
EGL_NONE};

EGLint configCount;
EGLConfig configs[1];

// Ask EGL for the best config matching our video settings
eglCheck(eglChooseConfig(display, attributes, configs, 1, &configCount));

// TODO: This should check EGL_CONFORMANT and pick the first conformant configuration.

return configs[0];
// Determine the number of available configs
EGLint configCount;
eglCheck(eglGetConfigs(display, nullptr, 0, &configCount));

// Retrieve the list of available configs
auto configs = std::make_unique<EGLConfig[]>(static_cast<std::size_t>(configCount));

eglCheck(eglGetConfigs(display, configs.get(), configCount, &configCount));

// Evaluate all the returned configs, and pick the best one
int bestScore = 0x7FFFFFFF;
EGLConfig bestConfig{};

for (std::size_t i = 0; i < static_cast<std::size_t>(configCount); ++i)
{
// Check mandatory attributes
int surfaceType;
int renderableType;
eglCheck(eglGetConfigAttrib(display, configs[i], EGL_SURFACE_TYPE, &surfaceType));
eglCheck(eglGetConfigAttrib(display, configs[i], EGL_RENDERABLE_TYPE, &renderableType));
if (!(surfaceType & (EGL_WINDOW_BIT | EGL_PBUFFER_BIT)) || !(renderableType & EGL_OPENGL_ES_BIT))
continue;

// Extract the components of the current config
int red;
int green;
int blue;
int alpha;
int depth;
int stencil;
int multiSampling;
int samples;
int caveat;
eglCheck(eglGetConfigAttrib(display, configs[i], EGL_RED_SIZE, &red));
eglCheck(eglGetConfigAttrib(display, configs[i], EGL_GREEN_SIZE, &green));
eglCheck(eglGetConfigAttrib(display, configs[i], EGL_BLUE_SIZE, &blue));
eglCheck(eglGetConfigAttrib(display, configs[i], EGL_ALPHA_SIZE, &alpha));
eglCheck(eglGetConfigAttrib(display, configs[i], EGL_DEPTH_SIZE, &depth));
eglCheck(eglGetConfigAttrib(display, configs[i], EGL_STENCIL_SIZE, &stencil));
eglCheck(eglGetConfigAttrib(display, configs[i], EGL_SAMPLE_BUFFERS, &multiSampling));
eglCheck(eglGetConfigAttrib(display, configs[i], EGL_SAMPLES, &samples));
eglCheck(eglGetConfigAttrib(display, configs[i], EGL_CONFIG_CAVEAT, &caveat));

// Evaluate the config
int color = red + green + blue + alpha;
int score = evaluateFormat(bitsPerPixel, settings, color, depth, stencil, multiSampling ? samples : 0, caveat == EGL_NONE, false);

// If it's better than the current best, make it the new best
if (score < bestScore)
{
bestScore = score;
bestConfig = configs[i];
}
}

assert(bestScore < 0x7FFFFFFF);

return bestConfig;
}


////////////////////////////////////////////////////////////
void EglContext::updateSettings()
{
m_settings.majorVersion = 1;
m_settings.minorVersion = 1;
m_settings.attributeFlags = ContextSettings::Default;
m_settings.depthBits = 0;
m_settings.stencilBits = 0;
m_settings.antialiasingLevel = 0;

EGLBoolean result = EGL_FALSE;
EGLint tmp = 0;

// Update the internal context settings with the current config
eglCheck(result = eglGetConfigAttrib(m_display, m_config, EGL_DEPTH_SIZE, &tmp));

if (result == EGL_FALSE)
err() << "Failed to retrieve EGL_DEPTH_SIZE" << std::endl;

m_settings.depthBits = static_cast<unsigned int>(tmp);
if (result != EGL_FALSE)
m_settings.depthBits = static_cast<unsigned int>(tmp);

eglCheck(result = eglGetConfigAttrib(m_display, m_config, EGL_STENCIL_SIZE, &tmp));

if (result == EGL_FALSE)
err() << "Failed to retrieve EGL_STENCIL_SIZE" << std::endl;
if (result != EGL_FALSE)
m_settings.stencilBits = static_cast<unsigned int>(tmp);

m_settings.stencilBits = static_cast<unsigned int>(tmp);
eglCheck(result = eglGetConfigAttrib(m_display, m_config, EGL_SAMPLE_BUFFERS, &tmp));

eglCheck(result = eglGetConfigAttrib(m_display, m_config, EGL_SAMPLES, &tmp));

if (result == EGL_FALSE)
err() << "Failed to retrieve EGL_SAMPLES" << std::endl;

m_settings.antialiasingLevel = static_cast<unsigned int>(tmp);
if ((result != EGL_FALSE) && tmp)
{
eglCheck(result = eglGetConfigAttrib(m_display, m_config, EGL_SAMPLES, &tmp));

m_settings.majorVersion = 1;
m_settings.minorVersion = 1;
m_settings.attributeFlags = ContextSettings::Default;
if (result != EGL_FALSE)
m_settings.antialiasingLevel = static_cast<unsigned int>(tmp);
}
}


Expand Down
30 changes: 18 additions & 12 deletions src/SFML/Window/GlContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,6 @@ std::vector<std::string> extensions;
// Load our extensions vector with the supported extensions
void loadExtensions()
{
extensions.clear();

auto glGetErrorFunc = reinterpret_cast<glGetErrorFuncType>(sf::priv::GlContext::getFunction("glGetError"));
auto glGetIntegervFunc = reinterpret_cast<glGetIntegervFuncType>(sf::priv::GlContext::getFunction("glGetIntegerv"));
auto glGetStringFunc = reinterpret_cast<glGetStringFuncType>(sf::priv::GlContext::getFunction("glGetString"));
Expand All @@ -290,21 +288,25 @@ void loadExtensions()

auto glGetStringiFunc = reinterpret_cast<glGetStringiFuncType>(sf::priv::GlContext::getFunction("glGetStringi"));

if (glGetErrorFunc() == GL_INVALID_ENUM || !glGetStringiFunc)
if (glGetErrorFunc() == GL_INVALID_ENUM || !majorVersion || !glGetStringiFunc)
{
// Try to load the < 3.0 way
const char* extensionString = reinterpret_cast<const char*>(glGetStringFunc(GL_EXTENSIONS));
assert(extensionString);

do
if (extensionString)
{
const char* extension = extensionString;
extensions.clear();

do
{
const char* extension = extensionString;

while (*extensionString && (*extensionString != ' '))
++extensionString;
while (*extensionString && (*extensionString != ' '))
++extensionString;

extensions.emplace_back(extension, extensionString);
} while (*extensionString++);
extensions.emplace_back(extension, extensionString);
} while (*extensionString++);
}
}
else
{
Expand All @@ -314,10 +316,14 @@ void loadExtensions()

if (numExtensions)
{
extensions.clear();

for (unsigned int i = 0; i < static_cast<unsigned int>(numExtensions); ++i)
{
const char* extensionString = reinterpret_cast<const char*>(glGetStringiFunc(GL_EXTENSIONS, i));
extensions.emplace_back(extensionString);

if (extensionString)
extensions.emplace_back(extensionString);
}
}
}
Expand Down Expand Up @@ -807,7 +813,7 @@ void GlContext::initialize(const ContextSettings& requestedSettings)
glGetIntegervFunc(GL_MAJOR_VERSION, &majorVersion);
glGetIntegervFunc(GL_MINOR_VERSION, &minorVersion);

if (glGetErrorFunc() != GL_INVALID_ENUM)
if ((glGetErrorFunc() != GL_INVALID_ENUM) && (majorVersion != 0))
{
m_settings.majorVersion = static_cast<unsigned int>(majorVersion);
m_settings.minorVersion = static_cast<unsigned int>(minorVersion);
Expand Down

0 comments on commit 6a3feda

Please sign in to comment.