blob: 639421a38f6c572a7d9d835fdb564aa9138cbe7c [file] [log] [blame]
//
// Copyright © 2012 Linaro Limited
//
// This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
//
// glmark2 is free software: you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// glmark2. If not, see <http://www.gnu.org/licenses/>.
//
// Authors:
// Jesse Barker
//
#include "egl-state.h"
#include "log.h"
#include "options.h"
#include "limits.h"
#include <iomanip>
#include <sstream>
using std::vector;
using std::string;
EglConfig::EglConfig(EGLDisplay dpy, EGLConfig config) :
handle_(config),
bufferSize_(0),
redSize_(0),
greenSize_(0),
blueSize_(0),
luminanceSize_(0),
alphaSize_(0),
alphaMaskSize_(0),
bindTexRGB_(false),
bindTexRGBA_(false),
bufferType_(EGL_RGB_BUFFER),
caveat_(0),
configID_(0),
conformant_(0),
depthSize_(0),
level_(0),
pbufferWidth_(0),
pbufferHeight_(0),
pbufferPixels_(0),
minSwapInterval_(0),
maxSwapInterval_(0),
nativeID_(0),
nativeType_(0),
nativeRenderable_(false),
sampleBuffers_(0),
samples_(0),
stencilSize_(0),
surfaceType_(0),
xparentType_(0),
xparentRedValue_(0),
xparentGreenValue_(0),
xparentBlueValue_(0)
{
vector<string> badAttribVec;
if (!eglGetConfigAttrib(dpy, handle_, EGL_CONFIG_ID, &configID_))
{
badAttribVec.push_back("EGL_CONFIG_ID");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_CONFIG_CAVEAT, &caveat_))
{
badAttribVec.push_back("EGL_CONFIG_CAVEAT");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_CONFORMANT, &conformant_))
{
badAttribVec.push_back("EGL_CONFORMANT");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_COLOR_BUFFER_TYPE, &bufferType_))
{
badAttribVec.push_back("EGL_COLOR_BUFFER_TYPE");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_BUFFER_SIZE, &bufferSize_))
{
badAttribVec.push_back("EGL_BUFFER_SIZE");
}
if (bufferType_ == EGL_RGB_BUFFER)
{
if (!eglGetConfigAttrib(dpy, handle_, EGL_RED_SIZE, &redSize_))
{
badAttribVec.push_back("EGL_RED_SIZE");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_GREEN_SIZE, &greenSize_))
{
badAttribVec.push_back("EGL_GREEN_SIZE");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_BLUE_SIZE, &blueSize_))
{
badAttribVec.push_back("EGL_BLUE_SIZE");
}
}
else
{
if (!eglGetConfigAttrib(dpy, handle_, EGL_LUMINANCE_SIZE, &luminanceSize_))
{
badAttribVec.push_back("EGL_LUMINANCE_SIZE");
}
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_ALPHA_SIZE, &alphaSize_))
{
badAttribVec.push_back("EGL_ALPHA_SIZE");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_ALPHA_MASK_SIZE, &alphaMaskSize_))
{
badAttribVec.push_back("EGL_ALPHA_MASK_SIZE");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_DEPTH_SIZE, &depthSize_))
{
badAttribVec.push_back("EGL_DEPTH_SIZE");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_STENCIL_SIZE, &stencilSize_))
{
badAttribVec.push_back("EGL_STENCIL_SIZE");
}
EGLint doBind(EGL_FALSE);
if (!eglGetConfigAttrib(dpy, handle_, EGL_BIND_TO_TEXTURE_RGB, &doBind))
{
badAttribVec.push_back("EGL_BIND_TO_TEXTURE_RGB");
}
bindTexRGB_ = (doBind == EGL_TRUE);
if (!eglGetConfigAttrib(dpy, handle_, EGL_BIND_TO_TEXTURE_RGBA, &doBind))
{
badAttribVec.push_back("EGL_BIND_TO_TEXTURE_RGBA");
}
bindTexRGBA_ = (doBind == EGL_TRUE);
if (!eglGetConfigAttrib(dpy, handle_, EGL_LEVEL, &level_))
{
badAttribVec.push_back("EGL_LEVEL");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_MAX_PBUFFER_WIDTH, &pbufferWidth_))
{
badAttribVec.push_back("EGL_MAX_PBUFFER_WIDTH");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_MAX_PBUFFER_HEIGHT, &pbufferHeight_))
{
badAttribVec.push_back("EGL_MAX_PBUFFER_HEIGHT");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_MAX_PBUFFER_PIXELS, &pbufferPixels_))
{
badAttribVec.push_back("EGL_MAX_PBUFFER_PIXELS");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_MIN_SWAP_INTERVAL, &minSwapInterval_))
{
badAttribVec.push_back("EGL_MIN_SWAP_INTERVAL");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_MAX_SWAP_INTERVAL, &maxSwapInterval_))
{
badAttribVec.push_back("EGL_MAX_SWAP_INTERVAL");
}
EGLint doNative(EGL_FALSE);
if (!eglGetConfigAttrib(dpy, handle_, EGL_NATIVE_RENDERABLE, &doNative))
{
badAttribVec.push_back("EGL_NATIVE_RENDERABLE");
}
nativeRenderable_ = (doNative == EGL_TRUE);
if (!eglGetConfigAttrib(dpy, handle_, EGL_NATIVE_VISUAL_TYPE, &nativeType_))
{
badAttribVec.push_back("EGL_NATIVE_VISUAL_TYPE");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_NATIVE_VISUAL_ID, &nativeID_))
{
badAttribVec.push_back("EGL_NATIVE_VISUAL_ID");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_SURFACE_TYPE, &surfaceType_))
{
badAttribVec.push_back("EGL_SURFACE_TYPE");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_SAMPLE_BUFFERS, &sampleBuffers_))
{
badAttribVec.push_back("EGL_SAMPLE_BUFFERS");
}
if (sampleBuffers_)
{
if (!eglGetConfigAttrib(dpy, handle_, EGL_SAMPLES, &samples_))
{
badAttribVec.push_back("EGL_SAMPLES");
}
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_TRANSPARENT_TYPE, &xparentType_))
{
badAttribVec.push_back("EGL_TRANSPARENT_TYPE");
}
//if (xparentType_ != EGL_NONE)
{
if (!eglGetConfigAttrib(dpy, handle_, EGL_TRANSPARENT_RED_VALUE, &xparentRedValue_))
{
badAttribVec.push_back("EGL_TRANSPARENT_RED_VALUE");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_TRANSPARENT_GREEN_VALUE, &xparentGreenValue_))
{
badAttribVec.push_back("EGL_TRANSPARENT_GREEN_VALUE");
}
if (!eglGetConfigAttrib(dpy, handle_, EGL_TRANSPARENT_BLUE_VALUE, &xparentBlueValue_))
{
badAttribVec.push_back("EGL_TRANSPARENT_BLUE_VALUE");
}
}
if (!badAttribVec.empty())
{
Log::error("Failed to get the following config attributes for config 0x%x:\n",
config);
for (vector<string>::const_iterator attribIt = badAttribVec.begin();
attribIt != badAttribVec.end();
attribIt++)
{
Log::error("%s\n", attribIt->c_str());
}
}
}
void
EglConfig::print_header()
{
Log::debug("\n");
Log::debug(" cfg buf rgb colorbuffer dp st config native support surface sample\n");
Log::debug(" id sz lum r g b a th cl caveat render visid type buf ns\n");
Log::debug("------------------------------------------------------------------------\n");
}
void
EglConfig::print() const
{
std::ostringstream s;
s.setf(std::ios::showbase);
s.fill(' ');
s << std::setw(7) << std::hex << configID_;
s << std::setw(4) << std::dec << bufferSize_;
if (bufferType_ == EGL_RGB_BUFFER)
{
s << std::setw(5) << "rgb";
s << std::setw(3) << redSize_;
s << std::setw(3) << greenSize_;
s << std::setw(3) << blueSize_;
}
else
{
s << std::setw(5) << "lum";
s << std::setw(3) << luminanceSize_;
s << std::setw(3) << 0;
s << std::setw(3) << 0;
}
s << std::setw(3) << alphaSize_;
s << std::setw(4) << depthSize_;
s << std::setw(3) << stencilSize_;
string caveat("None");
switch (caveat_)
{
case EGL_SLOW_CONFIG:
caveat = string("Slow");
break;
case EGL_NON_CONFORMANT_CONFIG:
caveat = string("Ncon");
break;
case EGL_NONE:
// Initialized to none.
break;
}
s << std::setw(7) << caveat;
string doNative(nativeRenderable_ ? "true" : "false");
s << std::setw(7) << doNative;
s << std::setw(8) << std::hex << nativeID_;
s << std::setw(8) << std::hex << surfaceType_;
s << std::setw(4) << std::dec << sampleBuffers_;
s << std::setw(3) << std::dec << samples_;
Log::debug("%s\n", s.str().c_str());
}
bool
EGLState::init_display(EGLNativeDisplayType native_display, GLVisualConfig& visual_config)
{
native_display_ = native_display;
visual_config_ = visual_config;
return gotValidDisplay();
}
bool
EGLState::init_surface(EGLNativeWindowType native_window)
{
native_window_ = reinterpret_cast<EGLNativeWindowType>(native_window);
return gotValidSurface();
}
void
EGLState::swap()
{
eglSwapBuffers(egl_display_, egl_surface_);
}
bool
EGLState::gotValidDisplay()
{
if (egl_display_)
return true;
egl_display_ = eglGetDisplay(native_display_);
if (!egl_display_) {
Log::error("eglGetDisplay() failed with error: 0x%x\n", eglGetError());
return false;
}
int egl_major(-1);
int egl_minor(-1);
if (!eglInitialize(egl_display_, &egl_major, &egl_minor)) {
Log::error("eglInitialize() failed with error: 0x%x\n", eglGetError());
egl_display_ = 0;
return false;
}
#if USE_GLESv2
EGLenum apiType(EGL_OPENGL_ES_API);
#elif USE_GL
EGLenum apiType(EGL_OPENGL_API);
#endif
if (!eglBindAPI(apiType)) {
Log::error("Failed to bind api EGL_OPENGL_ES_API\n");
return false;
}
return true;
}
void
EGLState::get_glvisualconfig(EGLConfig config, GLVisualConfig& visual_config)
{
eglGetConfigAttrib(egl_display_, config, EGL_BUFFER_SIZE, &visual_config.buffer);
eglGetConfigAttrib(egl_display_, config, EGL_RED_SIZE, &visual_config.red);
eglGetConfigAttrib(egl_display_, config, EGL_GREEN_SIZE, &visual_config.green);
eglGetConfigAttrib(egl_display_, config, EGL_BLUE_SIZE, &visual_config.blue);
eglGetConfigAttrib(egl_display_, config, EGL_ALPHA_SIZE, &visual_config.alpha);
eglGetConfigAttrib(egl_display_, config, EGL_DEPTH_SIZE, &visual_config.depth);
eglGetConfigAttrib(egl_display_, config, EGL_STENCIL_SIZE, &visual_config.stencil);
}
EGLConfig
EGLState::select_best_config(std::vector<EGLConfig>& configs)
{
int best_score(INT_MIN);
EGLConfig best_config(0);
/*
* Go through all the configs and choose the one with the best score,
* i.e., the one better matching the requested config.
*/
for (std::vector<EGLConfig>::const_iterator iter = configs.begin();
iter != configs.end();
iter++)
{
const EGLConfig config(*iter);
GLVisualConfig vc;
int score;
get_glvisualconfig(config, vc);
score = vc.match_score(visual_config_);
if (score > best_score) {
best_score = score;
best_config = config;
}
}
return best_config;
}
bool
EGLState::gotValidConfig()
{
if (egl_config_)
return true;
if (!gotValidDisplay())
return false;
const EGLint config_attribs[] = {
EGL_RED_SIZE, visual_config_.red,
EGL_GREEN_SIZE, visual_config_.green,
EGL_BLUE_SIZE, visual_config_.blue,
EGL_ALPHA_SIZE, visual_config_.alpha,
EGL_DEPTH_SIZE, visual_config_.depth,
EGL_STENCIL_SIZE, visual_config_.stencil,
#if USE_GLESv2
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
#elif USE_GL
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
#endif
EGL_NONE
};
// Find out how many configs match the attributes.
EGLint num_configs(0);
if (!eglChooseConfig(egl_display_, config_attribs, 0, 0, &num_configs)) {
Log::error("eglChooseConfig() (count query) failed with error: %d\n",
eglGetError());
return false;
}
if (num_configs == 0) {
Log::error("eglChooseConfig() didn't return any configs\n");
return false;
}
// Get all the matching configs
vector<EGLConfig> configs(num_configs);
if (!eglChooseConfig(egl_display_, config_attribs, &configs.front(),
num_configs, &num_configs))
{
Log::error("eglChooseConfig() failed with error: %d\n",
eglGetError());
return false;
}
// Select the best matching config
egl_config_ = select_best_config(configs);
vector<EglConfig> configVec;
for (vector<EGLConfig>::const_iterator configIt = configs.begin();
configIt != configs.end();
configIt++)
{
EglConfig cfg(egl_display_, *configIt);
configVec.push_back(cfg);
if (*configIt == egl_config_) {
best_config_ = cfg;
}
}
// Print out the config information, and let the user know the decision
// about the "best" one with respect to the options.
unsigned int lineNumber(0);
Log::debug("Got %u suitable EGLConfigs:\n", num_configs);
for (vector<EglConfig>::const_iterator configIt = configVec.begin();
configIt != configVec.end();
configIt++, lineNumber++)
{
if (!(lineNumber % 32))
{
configIt->print_header();
}
configIt->print();
}
Log::debug("\n");
Log::debug("Best EGLConfig ID: 0x%x\n", best_config_.configID());
return true;
}
bool
EGLState::gotValidSurface()
{
if (egl_surface_)
return true;
if (!gotValidDisplay())
return false;
if (!gotValidConfig())
return false;
egl_surface_ = eglCreateWindowSurface(egl_display_, egl_config_, native_window_, 0);
if (!egl_surface_) {
Log::error("eglCreateWindowSurface failed with error: 0x%x\n", eglGetError());
return false;
}
return true;
}
bool
EGLState::gotValidContext()
{
if (egl_context_)
return true;
if (!gotValidDisplay())
return false;
if (!gotValidConfig())
return false;
static const EGLint context_attribs[] = {
#ifdef USE_GLESv2
EGL_CONTEXT_CLIENT_VERSION, 2,
#endif
EGL_NONE
};
egl_context_ = eglCreateContext(egl_display_, egl_config_,
EGL_NO_CONTEXT, context_attribs);
if (!egl_context_) {
Log::error("eglCreateContext() failed with error: 0x%x\n",
eglGetError());
return false;
}
return true;
}
bool
EGLState::valid()
{
if (!gotValidDisplay())
return false;
if (!gotValidConfig())
return false;
if (!gotValidSurface())
return false;
if (!gotValidContext())
return false;
if (egl_context_ == eglGetCurrentContext())
return true;
if (!eglMakeCurrent(egl_display_, egl_surface_, egl_surface_, egl_context_)) {
Log::error("eglMakeCurrent failed with error: 0x%x\n", eglGetError());
return false;
}
if (!eglSwapInterval(egl_display_, 0)) {
Log::info("** Failed to set swap interval. Results may be bounded above by refresh rate.\n");
}
return true;
}
bool
EGLState::gotNativeConfig(int& vid)
{
if (!gotValidConfig())
return false;
EGLint native_id;
if (!eglGetConfigAttrib(egl_display_, egl_config_, EGL_NATIVE_VISUAL_ID,
&native_id))
{
Log::debug("Failed to get native visual id for EGLConfig 0x%x\n", egl_config_);
return false;
}
vid = native_id;
return true;
}
bool
EGLState::reset()
{
if (!gotValidDisplay()) {
return false;
}
if (!egl_context_) {
return true;
}
if (EGL_FALSE == eglDestroyContext(egl_display_, egl_context_)) {
Log::debug("eglDestroyContext failed with error: 0x%x\n", eglGetError());
}
egl_context_ = 0;
return true;
}