Add another way to select a context in CEGLManager.

Emscripten can't use eglChooseConfig so far (it won't return best context, but just any), 
so we have to work with eglGetConfigs instead and figure out the best egl context.


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@5554 dfc29bdd-3216-0410-991c-e03cc46cb475
master
cutealien 2017-10-25 17:37:07 +00:00
parent 3d19965f91
commit 66530e3941
3 changed files with 374 additions and 114 deletions

View File

@ -103,6 +103,11 @@ void one_iter()
*/
int main()
{
/*
Printing out the build date/time is very useful to find troubles with unexpected browser-caches.
*/
printf("Build-date: %s %s\n", __DATE__, __TIME__);
SIrrlichtCreationParameters parameters;
/*
Create device flags for emscripten are still experimental
@ -118,6 +123,7 @@ int main()
parameters.DriverType = EDT_WEBGL1;
#endif //__EMSCRIPTEN__
parameters.LoggingLevel = ELL_DEBUG;
parameters.WindowSize = screenSize;
parameters.Stencilbuffer = false;
parameters.AntiAlias = 4;

View File

@ -7,6 +7,7 @@
#ifdef _IRR_COMPILE_WITH_EGL_MANAGER_
#include "irrString.h"
#include "irrArray.h"
#include "os.h"
#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
@ -126,125 +127,20 @@ bool CEGLManager::generateSurface()
EglWindow = (ANativeWindow*)Data.OGLESAndroid.Window;
#endif
EGLint EglOpenGLBIT = 0;
// We need proper OpenGL BIT.
switch (Params.DriverType)
{
case EDT_OGLES1:
EglOpenGLBIT = EGL_OPENGL_ES_BIT;
break;
case EDT_OGLES2:
case EDT_WEBGL1:
EglOpenGLBIT = EGL_OPENGL_ES2_BIT;
break;
default:
break;
}
EGLint Attribs[] =
{
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, Params.WithAlphaChannel ? 1:0,
EGL_BUFFER_SIZE, Params.Bits,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_DEPTH_SIZE, Params.ZBufferBits,
EGL_STENCIL_SIZE, Params.Stencilbuffer,
EGL_SAMPLE_BUFFERS, Params.AntiAlias ? 1:0,
EGL_SAMPLES, Params.AntiAlias,
#ifdef EGL_VERSION_1_3
EGL_RENDERABLE_TYPE, EglOpenGLBIT,
#if defined(_IRR_EMSCRIPTEN_PLATFORM_)
// eglChooseConfig is only implemented as stub in emscripten currently (version 1.37.22 at point of writing)
// So we have to chose ourselves.
EglConfig = chooseConfig(ECS_IRR_CHOOSE);
#else
EglConfig = chooseConfig(ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS);
#endif
EGL_NONE, 0
};
EglConfig = 0;
EGLint NumConfigs = 0;
u32 Steps = 5;
// Choose the best EGL config.
while (!eglChooseConfig(EglDisplay, Attribs, &EglConfig, 1, &NumConfigs) || !NumConfigs)
if ( EglConfig == 0 )
{
switch (Steps)
{
case 5: // samples
if (Attribs[19] > 2)
--Attribs[19];
else
{
Attribs[17] = 0;
Attribs[19] = 0;
--Steps;
}
break;
case 4: // alpha
if (Attribs[7])
{
Attribs[7] = 0;
if (Params.AntiAlias)
{
Attribs[17] = 1;
Attribs[19] = Params.AntiAlias;
Steps = 5;
}
}
else
--Steps;
break;
case 3: // stencil
if (Attribs[15])
{
Attribs[15] = 0;
if (Params.AntiAlias)
{
Attribs[17] = 1;
Attribs[19] = Params.AntiAlias;
Steps = 5;
}
}
else
--Steps;
break;
case 2: // depth size
if (Attribs[13] > 16)
{
Attribs[13] -= 8;
}
else
--Steps;
break;
case 1: // buffer size
if (Attribs[9] > 16)
{
Attribs[9] -= 8;
}
else
--Steps;
break;
default:
os::Printer::log("Could not get config for EGL display.");
return false;
}
os::Printer::log("Could not get config for EGL display.");
return false;
}
if (Params.AntiAlias && !Attribs[17])
os::Printer::log("No multisampling.");
if (Params.WithAlphaChannel && !Attribs[7])
os::Printer::log("No alpha.");
if (Params.Stencilbuffer && !Attribs[15])
os::Printer::log("No stencil buffer.");
if (Params.ZBufferBits > Attribs[13])
os::Printer::log("No full depth buffer.");
if (Params.Bits > Attribs[9])
os::Printer::log("No full color buffer.");
#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
EGLint Format = 0;
@ -273,6 +169,331 @@ bool CEGLManager::generateSurface()
return true;
}
EGLConfig CEGLManager::chooseConfig(EConfigStyle confStyle)
{
EGLConfig configResult = 0;
// Find proper OpenGL BIT.
EGLint eglOpenGLBIT = 0;
switch (Params.DriverType)
{
case EDT_OGLES1:
eglOpenGLBIT = EGL_OPENGL_ES_BIT;
break;
case EDT_OGLES2:
case EDT_WEBGL1:
eglOpenGLBIT = EGL_OPENGL_ES2_BIT;
break;
default:
break;
}
if ( confStyle == ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS )
{
EGLint Attribs[] =
{
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, Params.WithAlphaChannel ? 1:0,
EGL_BUFFER_SIZE, Params.Bits,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_DEPTH_SIZE, Params.ZBufferBits,
EGL_STENCIL_SIZE, Params.Stencilbuffer,
EGL_SAMPLE_BUFFERS, Params.AntiAlias ? 1:0,
EGL_SAMPLES, Params.AntiAlias,
#ifdef EGL_VERSION_1_3
EGL_RENDERABLE_TYPE, eglOpenGLBIT,
#endif
EGL_NONE, 0
};
EGLint numConfigs = 0;
u32 steps = 5;
// Choose the best EGL config.
while (!eglChooseConfig(EglDisplay, Attribs, &configResult, 1, &numConfigs) || !numConfigs)
{
switch (steps)
{
case 5: // samples
if (Attribs[19] > 2) // Params.AntiAlias
--Attribs[19];
else
{
Attribs[17] = 0; // Params.Stencilbuffer
Attribs[19] = 0; // Params.AntiAlias
--steps;
}
break;
case 4: // alpha
if (Attribs[7]) // Params.WithAlphaChannel
{
Attribs[7] = 0;
if (Params.AntiAlias)
{
Attribs[17] = 1;
Attribs[19] = Params.AntiAlias;
steps = 5;
}
}
else
--steps;
break;
case 3: // stencil
if (Attribs[15]) // Params.Stencilbuffer
{
Attribs[15] = 0;
if (Params.AntiAlias)
{
Attribs[17] = 1;
Attribs[19] = Params.AntiAlias;
steps = 5;
}
}
else
--steps;
break;
case 2: // depth size
if (Attribs[13] > 16) // Params.ZBufferBits
{
Attribs[13] -= 8;
}
else
--steps;
break;
case 1: // buffer size
if (Attribs[9] > 16) // Params.Bits
{
Attribs[9] -= 8;
}
else
--steps;
break;
default:
return 0;
}
}
if (Params.AntiAlias && !Attribs[17])
os::Printer::log("No multisampling.");
if (Params.WithAlphaChannel && !Attribs[7])
os::Printer::log("No alpha.");
if (Params.Stencilbuffer && !Attribs[15])
os::Printer::log("No stencil buffer.");
if (Params.ZBufferBits > Attribs[13])
os::Printer::log("No full depth buffer.");
if (Params.Bits > Attribs[9])
os::Printer::log("No full color buffer.");
}
else if ( confStyle == ECS_IRR_CHOOSE )
{
EGLint numConfigs;
if ( eglGetConfigs( EglDisplay, NULL, 0, &numConfigs) == EGL_FALSE )
{
testEGLError();
return 0;
}
if ( numConfigs <= 0 )
return 0;
EGLConfig * configs = new EGLConfig[numConfigs];
if ( eglGetConfigs( EglDisplay, configs, numConfigs, &numConfigs) == EGL_FALSE )
{
testEGLError();
return 0;
}
// Find the best one.
core::array<SConfigRating> ratings((u32)numConfigs);
for ( u32 i=0; i < (u32)numConfigs; ++i )
{
SConfigRating r;
r.config = configs[i];
r.rating = rateConfig(r.config, eglOpenGLBIT);
if ( r.rating >= 0 )
ratings.push_back(r);
}
if ( ratings.size() > 0 )
{
ratings.sort();
configResult = ratings[0].config;
if ( ratings[0].rating != 0 )
{
rateConfig(ratings[0].config, eglOpenGLBIT, true);
}
}
delete[] configs;
}
return configResult;
}
irr::s32 CEGLManager::rateConfig(EGLConfig config, EGLint eglOpenGLBIT, bool log)
{
// some values must be there or we ignore the config
#ifdef EGL_VERSION_1_3
EGLint attribRenderableType = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_RENDERABLE_TYPE, &attribRenderableType);
if ( attribRenderableType != eglOpenGLBIT )
{
if ( log )
os::Printer::log("EGL_RENDERABLE_TYPE != eglOpenGLBIT");
return -1;
}
#endif
EGLint attribSurfaceType = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_SURFACE_TYPE, &attribSurfaceType);
if ( attribSurfaceType != EGL_WINDOW_BIT )
{
if ( log )
os::Printer::log("EGL_SURFACE_TYPE!= EGL_WINDOW_BIT");
return -1;
}
// Generally we give a really bad rating if attributes are worse than requested
// We give a slight worse rating if attributes are not exact as requested
// And we use some priorities which might make sense (but not really fine-tuned,
// so if you think other priorities would be better don't worry about changing the values.
int rating = 0;
EGLint attribBufferSize = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_BUFFER_SIZE, &attribBufferSize);
if ( attribBufferSize < Params.Bits )
{
if ( log )
os::Printer::log("No full color buffer.");
rating += 100;
}
if ( attribBufferSize > Params.Bits )
{
if ( log )
os::Printer::log("Larger color buffer.", ELL_DEBUG);
++rating;
}
EGLint attribRedSize = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_RED_SIZE, &attribRedSize);
if ( attribRedSize < 5 && Params.Bits >= 4 )
rating += 100;
else if ( attribRedSize < 8 && Params.Bits >= 24)
rating += 10;
else if ( attribRedSize >= 8 && Params.Bits < 24 )
rating ++;
EGLint attribGreenSize = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_GREEN_SIZE, &attribGreenSize);
if ( attribGreenSize < 5 && Params.Bits >= 4 )
rating += 100;
else if ( attribGreenSize < 8 && Params.Bits >= 24)
rating += 10;
else if ( attribGreenSize >= 8 && Params.Bits < 24 )
rating ++;
EGLint attribBlueSize = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_BLUE_SIZE, &attribBlueSize);
if ( attribBlueSize < 5 && Params.Bits >= 4 )
rating += 100;
else if ( attribBlueSize < 8 && Params.Bits >= 24)
rating += 10;
else if ( attribBlueSize >= 8 && Params.Bits < 24 )
rating ++;
EGLint attribAlphaSize = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_ALPHA_SIZE, &attribAlphaSize);
if ( Params.WithAlphaChannel && attribAlphaSize == 0 )
{
if ( log )
os::Printer::log("No alpha.");
rating += 10;
}
else if ( !Params.WithAlphaChannel && attribAlphaSize > 0 )
{
if ( log )
os::Printer::log("Got alpha (unrequested).", ELL_DEBUG);
rating ++;
}
EGLint attribStencilSize = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_STENCIL_SIZE, &attribStencilSize);
if ( Params.Stencilbuffer && attribStencilSize == 0 )
{
if ( log )
os::Printer::log("No stencil buffer.");
rating += 10;
}
else if ( !Params.Stencilbuffer && attribStencilSize > 0 )
{
if ( log )
os::Printer::log("Got a stencil buffer (unrequested).", ELL_DEBUG);
rating ++;
}
EGLint attribDepthSize = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_DEPTH_SIZE, &attribDepthSize);
if ( attribDepthSize < Params.ZBufferBits )
{
if ( log )
{
if (attribDepthSize > 0)
os::Printer::log("No full depth buffer.");
else
os::Printer::log("No depth buffer.");
}
rating += 50;
}
else if ( attribDepthSize != Params.ZBufferBits )
{
if ( log )
{
if ( Params.ZBufferBits == 0 )
os::Printer::log("Got a depth buffer (unrequested).", ELL_DEBUG);
else
os::Printer::log("Got a larger depth buffer.", ELL_DEBUG);
}
rating ++;
}
EGLint attribSampleBuffers=0, attribSamples = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_SAMPLE_BUFFERS, &attribSampleBuffers);
eglGetConfigAttrib( EglDisplay, config, EGL_SAMPLES, &attribSamples);
if ( Params.AntiAlias && attribSampleBuffers == 0 )
{
if ( log )
os::Printer::log("No multisampling.");
rating += 20;
}
else if ( Params.AntiAlias && attribSampleBuffers && attribSamples < Params.AntiAlias )
{
if ( log )
os::Printer::log("Multisampling with less samples than requested.", ELL_DEBUG);
rating += 10;
}
else if ( Params.AntiAlias && attribSampleBuffers && attribSamples > Params.AntiAlias )
{
if ( log )
os::Printer::log("Multisampling with more samples than requested.", ELL_DEBUG);
rating += 5;
}
else if ( !Params.AntiAlias && attribSampleBuffers > 0 )
{
if ( log )
os::Printer::log("Got multisampling (unrequested).", ELL_DEBUG);
rating += 3;
}
return rating;
}
void CEGLManager::destroySurface()
{
if (EglSurface == EGL_NO_SURFACE)

View File

@ -74,6 +74,39 @@ namespace video
// Swap buffers.
bool swapBuffers();
protected:
enum EConfigStyle
{
// TODO: We should also have something like ECS_EGL_CHOOSE_CLOSEST
// which doesn't take first result of eglChooseConfigs,
// but the closest to requested parameters. eglChooseConfigs
// can return more than 1 result and first one might have
// "better" values than requested (more bits per pixel etc).
//! Get first result of eglChooseConfigs and if that fails try again by requesting simpler attributes
ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS,
//! We select our own best fit and avoid using eglChooseConfigs
ECS_IRR_CHOOSE,
};
EGLConfig chooseConfig(EConfigStyle confStyle);
// Check how close this config is to the parameters we requested
//! returns 0 is perfect, larger values are worse and < 0 is unusable.
irr::s32 rateConfig(EGLConfig config, EGLint eglOpenGLBIT, bool log=false);
// Helper to sort EGLConfig's. (because we got no std::pair....)
struct SConfigRating
{
EGLConfig config;
irr::s32 rating;
bool operator<(const SConfigRating& other) const
{
return rating < other.rating;
}
};
private:
bool testEGLError();