417 lines
14 KiB
C++
417 lines
14 KiB
C++
//
|
|
// Copyright 2002 The ANGLE Project Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
//
|
|
|
|
// Config.cpp: Implements the egl::Config class, describing the format, type
|
|
// and size for an egl::Surface. Implements EGLConfig and related functionality.
|
|
// [EGL 1.5] section 3.4 page 19.
|
|
|
|
#include "libANGLE/Config.h"
|
|
#include "libANGLE/AttributeMap.h"
|
|
|
|
#include <algorithm>
|
|
#include <vector>
|
|
|
|
#include <EGL/eglext.h>
|
|
#include "angle_gl.h"
|
|
|
|
#include "common/debug.h"
|
|
|
|
namespace egl
|
|
{
|
|
|
|
Config::Config()
|
|
: renderTargetFormat(GL_NONE),
|
|
depthStencilFormat(GL_NONE),
|
|
bufferSize(0),
|
|
redSize(0),
|
|
greenSize(0),
|
|
blueSize(0),
|
|
luminanceSize(0),
|
|
alphaSize(0),
|
|
alphaMaskSize(0),
|
|
bindToTextureRGB(EGL_FALSE),
|
|
bindToTextureRGBA(EGL_FALSE),
|
|
bindToTextureTarget(EGL_TEXTURE_2D),
|
|
colorBufferType(EGL_RGB_BUFFER),
|
|
configCaveat(EGL_NONE),
|
|
configID(0),
|
|
conformant(0),
|
|
depthSize(0),
|
|
level(0),
|
|
matchNativePixmap(EGL_FALSE),
|
|
maxPBufferWidth(0),
|
|
maxPBufferHeight(0),
|
|
maxPBufferPixels(0),
|
|
maxSwapInterval(0),
|
|
minSwapInterval(0),
|
|
nativeRenderable(EGL_FALSE),
|
|
nativeVisualID(0),
|
|
nativeVisualType(0),
|
|
renderableType(0),
|
|
sampleBuffers(0),
|
|
samples(0),
|
|
stencilSize(0),
|
|
surfaceType(0),
|
|
transparentType(EGL_NONE),
|
|
transparentRedValue(0),
|
|
transparentGreenValue(0),
|
|
transparentBlueValue(0),
|
|
optimalOrientation(0),
|
|
colorComponentType(EGL_COLOR_COMPONENT_TYPE_FIXED_EXT),
|
|
recordable(EGL_FALSE),
|
|
framebufferTarget(EGL_FALSE), // TODO: http://anglebug.com/4208
|
|
yInverted(EGL_FALSE)
|
|
{}
|
|
|
|
Config::~Config() {}
|
|
|
|
Config::Config(const Config &other) = default;
|
|
|
|
Config &Config::operator=(const Config &other) = default;
|
|
|
|
ConfigSet::ConfigSet() = default;
|
|
|
|
ConfigSet::ConfigSet(const ConfigSet &other) = default;
|
|
|
|
ConfigSet &ConfigSet::operator=(const ConfigSet &other) = default;
|
|
|
|
ConfigSet::~ConfigSet() = default;
|
|
|
|
EGLint ConfigSet::add(const Config &config)
|
|
{
|
|
// Set the config's ID to a small number that starts at 1 ([EGL 1.5] section 3.4)
|
|
EGLint id = static_cast<EGLint>(mConfigs.size()) + 1;
|
|
|
|
Config copyConfig(config);
|
|
copyConfig.configID = id;
|
|
mConfigs.insert(std::make_pair(id, copyConfig));
|
|
|
|
return id;
|
|
}
|
|
|
|
const Config &ConfigSet::get(EGLint id) const
|
|
{
|
|
ASSERT(mConfigs.find(id) != mConfigs.end());
|
|
return mConfigs.find(id)->second;
|
|
}
|
|
|
|
void ConfigSet::clear()
|
|
{
|
|
mConfigs.clear();
|
|
}
|
|
|
|
size_t ConfigSet::size() const
|
|
{
|
|
return mConfigs.size();
|
|
}
|
|
|
|
bool ConfigSet::contains(const Config *config) const
|
|
{
|
|
for (auto i = mConfigs.begin(); i != mConfigs.end(); i++)
|
|
{
|
|
const Config &item = i->second;
|
|
if (config == &item)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Function object used by STL sorting routines for ordering Configs according to [EGL 1.5]
|
|
// section 3.4.1.2 page 28.
|
|
class ConfigSorter
|
|
{
|
|
public:
|
|
explicit ConfigSorter(const AttributeMap &attributeMap)
|
|
: mWantRed(false),
|
|
mWantGreen(false),
|
|
mWantBlue(false),
|
|
mWantAlpha(false),
|
|
mWantLuminance(false)
|
|
{
|
|
scanForWantedComponents(attributeMap);
|
|
}
|
|
|
|
bool operator()(const Config *x, const Config *y) const { return (*this)(*x, *y); }
|
|
|
|
bool operator()(const Config &x, const Config &y) const
|
|
{
|
|
#define SORT(attribute) \
|
|
do \
|
|
{ \
|
|
if (x.attribute != y.attribute) \
|
|
return x.attribute < y.attribute; \
|
|
} while (0)
|
|
|
|
static_assert(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG,
|
|
"Unexpected EGL enum value.");
|
|
SORT(configCaveat);
|
|
|
|
static_assert(EGL_COLOR_COMPONENT_TYPE_FIXED_EXT < EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
|
|
"Unexpected order of EGL enums.");
|
|
SORT(colorComponentType);
|
|
|
|
static_assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER, "Unexpected EGL enum value.");
|
|
SORT(colorBufferType);
|
|
|
|
// By larger total number of color bits, only considering those that are requested to be >
|
|
// 0.
|
|
EGLint xComponentsSize = wantedComponentsSize(x);
|
|
EGLint yComponentsSize = wantedComponentsSize(y);
|
|
if (xComponentsSize != yComponentsSize)
|
|
{
|
|
return xComponentsSize > yComponentsSize;
|
|
}
|
|
|
|
SORT(bufferSize);
|
|
SORT(sampleBuffers);
|
|
SORT(samples);
|
|
SORT(depthSize);
|
|
SORT(stencilSize);
|
|
SORT(alphaMaskSize);
|
|
SORT(nativeVisualType);
|
|
SORT(configID);
|
|
|
|
#undef SORT
|
|
|
|
return false;
|
|
}
|
|
|
|
private:
|
|
static bool wantsComponent(const AttributeMap &attributeMap, EGLAttrib component)
|
|
{
|
|
// [EGL 1.5] section 3.4.1.2 page 30
|
|
// Sorting rule #3: by larger total number of color bits, not considering
|
|
// components that are 0 or don't-care.
|
|
EGLAttrib value = attributeMap.get(component, 0);
|
|
return value != 0 && value != EGL_DONT_CARE;
|
|
}
|
|
|
|
void scanForWantedComponents(const AttributeMap &attributeMap)
|
|
{
|
|
mWantRed = wantsComponent(attributeMap, EGL_RED_SIZE);
|
|
mWantGreen = wantsComponent(attributeMap, EGL_GREEN_SIZE);
|
|
mWantBlue = wantsComponent(attributeMap, EGL_BLUE_SIZE);
|
|
mWantAlpha = wantsComponent(attributeMap, EGL_ALPHA_SIZE);
|
|
mWantLuminance = wantsComponent(attributeMap, EGL_LUMINANCE_SIZE);
|
|
}
|
|
|
|
EGLint wantedComponentsSize(const Config &config) const
|
|
{
|
|
EGLint total = 0;
|
|
|
|
if (mWantRed)
|
|
total += config.redSize;
|
|
if (mWantGreen)
|
|
total += config.greenSize;
|
|
if (mWantBlue)
|
|
total += config.blueSize;
|
|
if (mWantAlpha)
|
|
total += config.alphaSize;
|
|
if (mWantLuminance)
|
|
total += config.luminanceSize;
|
|
|
|
return total;
|
|
}
|
|
|
|
bool mWantRed;
|
|
bool mWantGreen;
|
|
bool mWantBlue;
|
|
bool mWantAlpha;
|
|
bool mWantLuminance;
|
|
};
|
|
|
|
std::vector<const Config *> ConfigSet::filter(const AttributeMap &attributeMap) const
|
|
{
|
|
std::vector<const Config *> result;
|
|
result.reserve(mConfigs.size());
|
|
|
|
for (auto configIter = mConfigs.begin(); configIter != mConfigs.end(); configIter++)
|
|
{
|
|
const Config &config = configIter->second;
|
|
bool match = true;
|
|
|
|
for (auto attribIter = attributeMap.begin(); attribIter != attributeMap.end(); attribIter++)
|
|
{
|
|
EGLAttrib attributeKey = attribIter->first;
|
|
EGLAttrib attributeValue = attribIter->second;
|
|
|
|
if (attributeValue == EGL_DONT_CARE)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
switch (attributeKey)
|
|
{
|
|
case EGL_BUFFER_SIZE:
|
|
match = config.bufferSize >= attributeValue;
|
|
break;
|
|
case EGL_ALPHA_SIZE:
|
|
match = config.alphaSize >= attributeValue;
|
|
break;
|
|
case EGL_BLUE_SIZE:
|
|
match = config.blueSize >= attributeValue;
|
|
break;
|
|
case EGL_GREEN_SIZE:
|
|
match = config.greenSize >= attributeValue;
|
|
break;
|
|
case EGL_RED_SIZE:
|
|
match = config.redSize >= attributeValue;
|
|
break;
|
|
case EGL_DEPTH_SIZE:
|
|
match = config.depthSize >= attributeValue;
|
|
break;
|
|
case EGL_STENCIL_SIZE:
|
|
match = config.stencilSize >= attributeValue;
|
|
break;
|
|
case EGL_CONFIG_CAVEAT:
|
|
match = config.configCaveat == static_cast<EGLenum>(attributeValue);
|
|
break;
|
|
case EGL_CONFIG_ID:
|
|
match = config.configID == attributeValue;
|
|
break;
|
|
case EGL_LEVEL:
|
|
match = config.level == attributeValue;
|
|
break;
|
|
case EGL_NATIVE_RENDERABLE:
|
|
match = config.nativeRenderable == static_cast<EGLBoolean>(attributeValue);
|
|
break;
|
|
case EGL_NATIVE_VISUAL_TYPE:
|
|
match = config.nativeVisualType == attributeValue;
|
|
break;
|
|
case EGL_SAMPLES:
|
|
match = config.samples >= attributeValue;
|
|
break;
|
|
case EGL_SAMPLE_BUFFERS:
|
|
match = config.sampleBuffers >= attributeValue;
|
|
break;
|
|
case EGL_SURFACE_TYPE:
|
|
match = (config.surfaceType & attributeValue) == attributeValue;
|
|
break;
|
|
case EGL_TRANSPARENT_TYPE:
|
|
match = config.transparentType == static_cast<EGLenum>(attributeValue);
|
|
break;
|
|
case EGL_TRANSPARENT_BLUE_VALUE:
|
|
if (attributeMap.get(EGL_TRANSPARENT_TYPE, EGL_NONE) != EGL_NONE)
|
|
{
|
|
match = config.transparentBlueValue == attributeValue;
|
|
}
|
|
break;
|
|
case EGL_TRANSPARENT_GREEN_VALUE:
|
|
if (attributeMap.get(EGL_TRANSPARENT_TYPE, EGL_NONE) != EGL_NONE)
|
|
{
|
|
match = config.transparentGreenValue == attributeValue;
|
|
}
|
|
break;
|
|
case EGL_TRANSPARENT_RED_VALUE:
|
|
if (attributeMap.get(EGL_TRANSPARENT_TYPE, EGL_NONE) != EGL_NONE)
|
|
{
|
|
match = config.transparentRedValue == attributeValue;
|
|
}
|
|
break;
|
|
case EGL_BIND_TO_TEXTURE_RGB:
|
|
match = config.bindToTextureRGB == static_cast<EGLBoolean>(attributeValue);
|
|
break;
|
|
case EGL_BIND_TO_TEXTURE_RGBA:
|
|
match = config.bindToTextureRGBA == static_cast<EGLBoolean>(attributeValue);
|
|
break;
|
|
case EGL_BIND_TO_TEXTURE_TARGET_ANGLE:
|
|
match = config.bindToTextureTarget == static_cast<EGLenum>(attributeValue);
|
|
break;
|
|
case EGL_MIN_SWAP_INTERVAL:
|
|
match = config.minSwapInterval == attributeValue;
|
|
break;
|
|
case EGL_MAX_SWAP_INTERVAL:
|
|
match = config.maxSwapInterval == attributeValue;
|
|
break;
|
|
case EGL_LUMINANCE_SIZE:
|
|
match = config.luminanceSize >= attributeValue;
|
|
break;
|
|
case EGL_ALPHA_MASK_SIZE:
|
|
match = config.alphaMaskSize >= attributeValue;
|
|
break;
|
|
case EGL_COLOR_BUFFER_TYPE:
|
|
match = config.colorBufferType == static_cast<EGLenum>(attributeValue);
|
|
break;
|
|
case EGL_RENDERABLE_TYPE:
|
|
match = (config.renderableType & attributeValue) == attributeValue;
|
|
break;
|
|
case EGL_MATCH_NATIVE_PIXMAP:
|
|
match = false;
|
|
UNIMPLEMENTED();
|
|
break;
|
|
case EGL_CONFORMANT:
|
|
match = (config.conformant & attributeValue) == attributeValue;
|
|
break;
|
|
case EGL_MAX_PBUFFER_WIDTH:
|
|
match = config.maxPBufferWidth >= attributeValue;
|
|
break;
|
|
case EGL_MAX_PBUFFER_HEIGHT:
|
|
match = config.maxPBufferHeight >= attributeValue;
|
|
break;
|
|
case EGL_MAX_PBUFFER_PIXELS:
|
|
match = config.maxPBufferPixels >= attributeValue;
|
|
break;
|
|
case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE:
|
|
match = config.optimalOrientation == attributeValue;
|
|
break;
|
|
case EGL_COLOR_COMPONENT_TYPE_EXT:
|
|
match = config.colorComponentType == static_cast<EGLenum>(attributeValue);
|
|
break;
|
|
case EGL_RECORDABLE_ANDROID:
|
|
match = config.recordable == static_cast<EGLBoolean>(attributeValue);
|
|
break;
|
|
case EGL_FRAMEBUFFER_TARGET_ANDROID:
|
|
match = config.framebufferTarget == static_cast<EGLBoolean>(attributeValue);
|
|
break;
|
|
case EGL_Y_INVERTED_NOK:
|
|
match = config.yInverted == static_cast<EGLBoolean>(attributeValue);
|
|
break;
|
|
case EGL_MATCH_FORMAT_KHR:
|
|
if (attributeValue == EGL_NONE)
|
|
{
|
|
match = (config.surfaceType & EGL_LOCK_SURFACE_BIT_KHR) == 0;
|
|
}
|
|
else
|
|
{
|
|
match = config.matchFormat == attributeValue;
|
|
}
|
|
break;
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
|
|
if (!match)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (match)
|
|
{
|
|
result.push_back(&config);
|
|
}
|
|
}
|
|
|
|
// Sort the result
|
|
std::sort(result.begin(), result.end(), ConfigSorter(attributeMap));
|
|
|
|
return result;
|
|
}
|
|
|
|
ConfigSet::ConfigMap::iterator ConfigSet::begin()
|
|
{
|
|
return mConfigs.begin();
|
|
}
|
|
|
|
ConfigSet::ConfigMap::iterator ConfigSet::end()
|
|
{
|
|
return mConfigs.end();
|
|
}
|
|
} // namespace egl
|