| // | |
| // 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 |