| /*------------------------------------------------------------------------- |
| * drawElements Quality Program EGL Module |
| * --------------------------------------- |
| * |
| * Copyright 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Choose config reference implementation. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "teglChooseConfigReference.hpp" |
| |
| #include "egluUtil.hpp" |
| #include "egluConfigInfo.hpp" |
| #include "egluStrUtil.hpp" |
| #include "eglwLibrary.hpp" |
| #include "eglwEnums.hpp" |
| |
| #include <algorithm> |
| #include <vector> |
| #include <map> |
| |
| namespace deqp |
| { |
| namespace egl |
| { |
| |
| using namespace eglw; |
| using eglu::ConfigInfo; |
| |
| enum Criteria |
| { |
| CRITERIA_AT_LEAST = 0, |
| CRITERIA_EXACT, |
| CRITERIA_MASK, |
| CRITERIA_SPECIAL, |
| |
| CRITERIA_LAST |
| }; |
| |
| enum SortOrder |
| { |
| SORTORDER_NONE = 0, |
| SORTORDER_SMALLER, |
| SORTORDER_SPECIAL, |
| |
| SORTORDER_LAST |
| }; |
| |
| struct AttribRule |
| { |
| EGLenum name; |
| EGLint value; |
| Criteria criteria; |
| SortOrder sortOrder; |
| |
| AttribRule (void) |
| : name (EGL_NONE) |
| , value (EGL_NONE) |
| , criteria (CRITERIA_LAST) |
| , sortOrder (SORTORDER_LAST) |
| { |
| } |
| |
| AttribRule (EGLenum name_, EGLint value_, Criteria criteria_, SortOrder sortOrder_) |
| : name (name_) |
| , value (value_) |
| , criteria (criteria_) |
| , sortOrder (sortOrder_) |
| { |
| } |
| }; |
| |
| class SurfaceConfig |
| { |
| private: |
| static int getCaveatRank (EGLenum caveat) |
| { |
| switch (caveat) |
| { |
| case EGL_NONE: return 0; |
| case EGL_SLOW_CONFIG: return 1; |
| case EGL_NON_CONFORMANT_CONFIG: return 2; |
| default: |
| TCU_THROW(TestError, (std::string("Unknown config caveat: ") + eglu::getConfigCaveatStr(caveat).toString()).c_str()); |
| } |
| } |
| |
| static int getColorBufferTypeRank (EGLenum type) |
| { |
| switch (type) |
| { |
| case EGL_RGB_BUFFER: return 0; |
| case EGL_LUMINANCE_BUFFER: return 1; |
| case EGL_YUV_BUFFER_EXT: return 2; |
| default: |
| TCU_THROW(TestError, (std::string("Unknown color buffer type: ") + eglu::getColorBufferTypeStr(type).toString()).c_str()); |
| } |
| } |
| |
| typedef bool (*CompareFunc) (const SurfaceConfig& a, const SurfaceConfig& b); |
| |
| static bool compareCaveat (const SurfaceConfig& a, const SurfaceConfig& b) |
| { |
| return getCaveatRank((EGLenum)a.m_info.configCaveat) < getCaveatRank((EGLenum)b.m_info.configCaveat); |
| } |
| |
| static bool compareColorBufferType (const SurfaceConfig& a, const SurfaceConfig& b) |
| { |
| return getColorBufferTypeRank((EGLenum)a.m_info.colorBufferType) < getColorBufferTypeRank((EGLenum)b.m_info.colorBufferType); |
| } |
| |
| static bool compareColorBufferBits (const SurfaceConfig& a, const SurfaceConfig& b, const tcu::BVec4& specifiedRGBColors, const tcu::BVec2& specifiedLuminanceColors) |
| { |
| DE_ASSERT(a.m_info.colorBufferType == b.m_info.colorBufferType); |
| switch (a.m_info.colorBufferType) |
| { |
| case EGL_RGB_BUFFER: |
| { |
| const tcu::IVec4 mask (specifiedRGBColors.cast<deInt32>()); |
| |
| return (a.m_info.redSize * mask[0] + a.m_info.greenSize * mask[1] + a.m_info.blueSize * mask[2] + a.m_info.alphaSize * mask[3]) |
| > (b.m_info.redSize * mask[0] + b.m_info.greenSize * mask[1] + b.m_info.blueSize * mask[2] + b.m_info.alphaSize * mask[3]); |
| } |
| |
| case EGL_LUMINANCE_BUFFER: |
| { |
| const tcu::IVec2 mask (specifiedLuminanceColors.cast<deInt32>()); |
| |
| return (a.m_info.luminanceSize * mask[0] + a.m_info.alphaSize * mask[1]) > (b.m_info.luminanceSize * mask[0] + b.m_info.alphaSize * mask[1]); |
| } |
| |
| case EGL_YUV_BUFFER_EXT: |
| // \todo [mika 2015-05-05] Sort YUV configs correctly. Currently all YUV configs are non-conformant and ordering can be relaxed. |
| return true; |
| |
| default: |
| DE_ASSERT(DE_FALSE); |
| return true; |
| } |
| } |
| |
| template <EGLenum Attribute> |
| static bool compareAttributeSmaller (const SurfaceConfig& a, const SurfaceConfig& b) |
| { |
| return a.getAttribute(Attribute) < b.getAttribute(Attribute); |
| } |
| public: |
| SurfaceConfig (EGLConfig config, ConfigInfo &info) |
| : m_config(config) |
| , m_info(info) |
| { |
| } |
| |
| EGLConfig getEglConfig (void) const |
| { |
| return m_config; |
| } |
| |
| EGLint getAttribute (const EGLenum attribute) const |
| { |
| return m_info.getAttribute(attribute); |
| } |
| |
| friend bool operator== (const SurfaceConfig& a, const SurfaceConfig& b) |
| { |
| for (std::map<EGLenum, AttribRule>::const_iterator iter = SurfaceConfig::defaultRules.begin(); iter != SurfaceConfig::defaultRules.end(); iter++) |
| { |
| const EGLenum attribute = iter->first; |
| |
| if (a.getAttribute(attribute) != b.getAttribute(attribute)) return false; |
| } |
| return true; |
| } |
| |
| bool compareTo (const SurfaceConfig& b, const tcu::BVec4& specifiedRGBColors, const tcu::BVec2& specifiedLuminanceColors) const |
| { |
| static const SurfaceConfig::CompareFunc compareFuncs[] = |
| { |
| SurfaceConfig::compareCaveat, |
| SurfaceConfig::compareColorBufferType, |
| DE_NULL, // SurfaceConfig::compareColorBufferBits, |
| SurfaceConfig::compareAttributeSmaller<EGL_BUFFER_SIZE>, |
| SurfaceConfig::compareAttributeSmaller<EGL_SAMPLE_BUFFERS>, |
| SurfaceConfig::compareAttributeSmaller<EGL_SAMPLES>, |
| SurfaceConfig::compareAttributeSmaller<EGL_DEPTH_SIZE>, |
| SurfaceConfig::compareAttributeSmaller<EGL_STENCIL_SIZE>, |
| SurfaceConfig::compareAttributeSmaller<EGL_ALPHA_MASK_SIZE>, |
| SurfaceConfig::compareAttributeSmaller<EGL_CONFIG_ID> |
| }; |
| |
| if (*this == b) |
| return false; // std::sort() can compare object to itself. |
| |
| for (int ndx = 0; ndx < (int)DE_LENGTH_OF_ARRAY(compareFuncs); ndx++) |
| { |
| if (!compareFuncs[ndx]) |
| { |
| if (compareColorBufferBits(*this, b, specifiedRGBColors, specifiedLuminanceColors)) |
| return true; |
| else if (compareColorBufferBits(b, *this, specifiedRGBColors, specifiedLuminanceColors)) |
| return false; |
| |
| continue; |
| } |
| |
| if (compareFuncs[ndx](*this, b)) |
| return true; |
| else if (compareFuncs[ndx](b, *this)) |
| return false; |
| } |
| |
| TCU_FAIL("Unable to compare configs - duplicate ID?"); |
| } |
| |
| static const std::map<EGLenum, AttribRule> defaultRules; |
| |
| static std::map<EGLenum, AttribRule> initAttribRules (void) |
| { |
| // \todo [2011-03-24 pyry] From EGL 1.4 spec - check that this is valid for other versions as well |
| std::map<EGLenum, AttribRule> rules; |
| |
| // Attribute Default Selection Criteria Sort Order Sort Priority |
| rules[EGL_BUFFER_SIZE] = AttribRule(EGL_BUFFER_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SMALLER); // 4 |
| rules[EGL_RED_SIZE] = AttribRule(EGL_RED_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SPECIAL); // 3 |
| rules[EGL_GREEN_SIZE] = AttribRule(EGL_GREEN_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SPECIAL); // 3 |
| rules[EGL_BLUE_SIZE] = AttribRule(EGL_BLUE_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SPECIAL); // 3 |
| rules[EGL_LUMINANCE_SIZE] = AttribRule(EGL_LUMINANCE_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SPECIAL); // 3 |
| rules[EGL_ALPHA_SIZE] = AttribRule(EGL_ALPHA_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SPECIAL); // 3 |
| rules[EGL_ALPHA_MASK_SIZE] = AttribRule(EGL_ALPHA_MASK_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SMALLER); // 9 |
| rules[EGL_BIND_TO_TEXTURE_RGB] = AttribRule(EGL_BIND_TO_TEXTURE_RGB, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); |
| rules[EGL_BIND_TO_TEXTURE_RGBA] = AttribRule(EGL_BIND_TO_TEXTURE_RGBA, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); |
| rules[EGL_COLOR_BUFFER_TYPE] = AttribRule(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, CRITERIA_EXACT, SORTORDER_NONE); // 2 |
| rules[EGL_CONFIG_CAVEAT] = AttribRule(EGL_CONFIG_CAVEAT, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_SPECIAL); // 1 |
| rules[EGL_CONFIG_ID] = AttribRule(EGL_CONFIG_ID, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_SMALLER); // 11 |
| rules[EGL_CONFORMANT] = AttribRule(EGL_CONFORMANT, 0, CRITERIA_MASK, SORTORDER_NONE); |
| rules[EGL_DEPTH_SIZE] = AttribRule(EGL_DEPTH_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SMALLER); // 7 |
| rules[EGL_LEVEL] = AttribRule(EGL_LEVEL, 0, CRITERIA_EXACT, SORTORDER_NONE); |
| rules[EGL_MATCH_NATIVE_PIXMAP] = AttribRule(EGL_MATCH_NATIVE_PIXMAP, EGL_NONE, CRITERIA_SPECIAL, SORTORDER_NONE); |
| rules[EGL_MAX_SWAP_INTERVAL] = AttribRule(EGL_MAX_SWAP_INTERVAL, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); |
| rules[EGL_MIN_SWAP_INTERVAL] = AttribRule(EGL_MIN_SWAP_INTERVAL, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); |
| rules[EGL_NATIVE_RENDERABLE] = AttribRule(EGL_NATIVE_RENDERABLE, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); |
| rules[EGL_NATIVE_VISUAL_TYPE] = AttribRule(EGL_NATIVE_VISUAL_TYPE, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_SPECIAL); // 10 |
| rules[EGL_RENDERABLE_TYPE] = AttribRule(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT, CRITERIA_MASK, SORTORDER_NONE); |
| rules[EGL_SAMPLE_BUFFERS] = AttribRule(EGL_SAMPLE_BUFFERS, 0, CRITERIA_AT_LEAST, SORTORDER_SMALLER); // 5 |
| rules[EGL_SAMPLES] = AttribRule(EGL_SAMPLES, 0, CRITERIA_AT_LEAST, SORTORDER_SMALLER); // 6 |
| rules[EGL_STENCIL_SIZE] = AttribRule(EGL_STENCIL_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SMALLER); // 8 |
| rules[EGL_SURFACE_TYPE] = AttribRule(EGL_SURFACE_TYPE, EGL_WINDOW_BIT, CRITERIA_MASK, SORTORDER_NONE); |
| rules[EGL_TRANSPARENT_TYPE] = AttribRule(EGL_TRANSPARENT_TYPE, EGL_NONE, CRITERIA_EXACT, SORTORDER_NONE); |
| rules[EGL_TRANSPARENT_RED_VALUE] = AttribRule(EGL_TRANSPARENT_RED_VALUE, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); |
| rules[EGL_TRANSPARENT_GREEN_VALUE] = AttribRule(EGL_TRANSPARENT_GREEN_VALUE, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); |
| rules[EGL_TRANSPARENT_BLUE_VALUE] = AttribRule(EGL_TRANSPARENT_BLUE_VALUE, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); |
| |
| return rules; |
| } |
| private: |
| EGLConfig m_config; |
| ConfigInfo m_info; |
| }; |
| |
| const std::map<EGLenum, AttribRule> SurfaceConfig::defaultRules = SurfaceConfig::initAttribRules(); |
| |
| class CompareConfigs |
| { |
| public: |
| CompareConfigs (const tcu::BVec4& specifiedRGBColors, const tcu::BVec2& specifiedLuminanceColors) |
| : m_specifiedRGBColors (specifiedRGBColors) |
| , m_specifiedLuminanceColors (specifiedLuminanceColors) |
| { |
| } |
| |
| bool operator() (const SurfaceConfig& a, const SurfaceConfig& b) |
| { |
| return a.compareTo(b, m_specifiedRGBColors, m_specifiedLuminanceColors); |
| } |
| |
| private: |
| const tcu::BVec4 m_specifiedRGBColors; |
| const tcu::BVec2 m_specifiedLuminanceColors; |
| }; |
| |
| class ConfigFilter |
| { |
| private: |
| std::map<EGLenum, AttribRule> m_rules; |
| public: |
| ConfigFilter () |
| : m_rules(SurfaceConfig::defaultRules) |
| { |
| } |
| |
| void setValue (EGLenum name, EGLint value) |
| { |
| DE_ASSERT(SurfaceConfig::defaultRules.find(name) != SurfaceConfig::defaultRules.end()); |
| m_rules[name].value = value; |
| } |
| |
| void setValues (std::vector<std::pair<EGLenum, EGLint> > values) |
| { |
| for (size_t ndx = 0; ndx < values.size(); ndx++) |
| { |
| const EGLenum name = values[ndx].first; |
| const EGLint value = values[ndx].second; |
| |
| setValue(name, value); |
| } |
| } |
| |
| AttribRule getAttribute (EGLenum name) |
| { |
| DE_ASSERT(SurfaceConfig::defaultRules.find(name) != SurfaceConfig::defaultRules.end()); |
| return m_rules[name]; |
| } |
| |
| bool isMatch (const SurfaceConfig& config) |
| { |
| for (std::map<EGLenum, AttribRule>::const_iterator iter = m_rules.begin(); iter != m_rules.end(); iter++) |
| { |
| const AttribRule rule = iter->second; |
| |
| if (rule.value == EGL_DONT_CARE) |
| continue; |
| else if (rule.name == EGL_MATCH_NATIVE_PIXMAP) |
| TCU_CHECK(rule.value == EGL_NONE); // Not supported |
| else if (rule.name == EGL_TRANSPARENT_RED_VALUE || rule.name == EGL_TRANSPARENT_GREEN_VALUE || rule.name == EGL_TRANSPARENT_BLUE_VALUE) |
| continue; |
| else |
| { |
| const EGLint cfgValue = config.getAttribute(rule.name); |
| |
| switch (rule.criteria) |
| { |
| case CRITERIA_EXACT: |
| if (rule.value != cfgValue) |
| return false; |
| break; |
| |
| case CRITERIA_AT_LEAST: |
| if (rule.value > cfgValue) |
| return false; |
| break; |
| |
| case CRITERIA_MASK: |
| if ((rule.value & cfgValue) != rule.value) |
| return false; |
| break; |
| |
| default: |
| TCU_FAIL("Unknown criteria"); |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| tcu::BVec4 getSpecifiedRGBColors (void) |
| { |
| const EGLenum bitAttribs[] = |
| { |
| EGL_RED_SIZE, |
| EGL_GREEN_SIZE, |
| EGL_BLUE_SIZE, |
| EGL_ALPHA_SIZE |
| }; |
| |
| tcu::BVec4 result; |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(bitAttribs); ndx++) |
| { |
| const EGLenum attrib = bitAttribs[ndx]; |
| const EGLint value = getAttribute(attrib).value; |
| |
| if (value != 0 && value != EGL_DONT_CARE) |
| result[ndx] = true; |
| else |
| result[ndx] = false; |
| } |
| |
| return result; |
| } |
| |
| tcu::BVec2 getSpecifiedLuminanceColors (void) |
| { |
| const EGLenum bitAttribs[] = |
| { |
| EGL_LUMINANCE_SIZE, |
| EGL_ALPHA_SIZE |
| }; |
| |
| tcu::BVec2 result; |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(bitAttribs); ndx++) |
| { |
| const EGLenum attrib = bitAttribs[ndx]; |
| const EGLint value = getAttribute(attrib).value; |
| |
| if (value != 0 && value != EGL_DONT_CARE) |
| result[ndx] = true; |
| else |
| result[ndx] = false; |
| } |
| |
| return result; |
| } |
| |
| std::vector<SurfaceConfig> filter (const std::vector<SurfaceConfig>& configs) |
| { |
| std::vector<SurfaceConfig> out; |
| |
| for (std::vector<SurfaceConfig>::const_iterator iter = configs.begin(); iter != configs.end(); iter++) |
| { |
| if (isMatch(*iter)) out.push_back(*iter); |
| } |
| |
| return out; |
| } |
| }; |
| |
| void chooseConfigReference (const Library& egl, EGLDisplay display, std::vector<EGLConfig>& dst, const std::vector<std::pair<EGLenum, EGLint> >& attributes) |
| { |
| // Get all configs |
| std::vector<EGLConfig> eglConfigs = eglu::getConfigs(egl, display); |
| |
| // Config infos |
| std::vector<ConfigInfo> configInfos; |
| configInfos.resize(eglConfigs.size()); |
| for (size_t ndx = 0; ndx < eglConfigs.size(); ndx++) |
| eglu::queryConfigInfo(egl, display, eglConfigs[ndx], &configInfos[ndx]); |
| |
| // Pair configs with info |
| std::vector<SurfaceConfig> configs; |
| for (size_t ndx = 0; ndx < eglConfigs.size(); ndx++) |
| configs.push_back(SurfaceConfig(eglConfigs[ndx], configInfos[ndx])); |
| |
| // Filter configs |
| ConfigFilter configFilter; |
| configFilter.setValues(attributes); |
| |
| std::vector<SurfaceConfig> filteredConfigs = configFilter.filter(configs); |
| |
| // Sort configs |
| std::sort(filteredConfigs.begin(), filteredConfigs.end(), CompareConfigs(configFilter.getSpecifiedRGBColors(), configFilter.getSpecifiedLuminanceColors())); |
| |
| // Write to dst list |
| dst.resize(filteredConfigs.size()); |
| for (size_t ndx = 0; ndx < filteredConfigs.size(); ndx++) |
| dst[ndx] = filteredConfigs[ndx].getEglConfig(); |
| } |
| |
| } // egl |
| } // deqp |