/*------------------------------------------------------------------------- * 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 "deSTLUtil.hpp" #include #include #include 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()); } } static int getYuvOrderRank (EGLenum order) { switch (order) { case EGL_NONE: return 0; case EGL_YUV_ORDER_YUV_EXT: return 1; case EGL_YUV_ORDER_YVU_EXT: return 2; case EGL_YUV_ORDER_YUYV_EXT: return 3; case EGL_YUV_ORDER_YVYU_EXT: return 4; case EGL_YUV_ORDER_UYVY_EXT: return 5; case EGL_YUV_ORDER_VYUY_EXT: return 6; case EGL_YUV_ORDER_AYUV_EXT: return 7; default: TCU_THROW(TestError, (std::string("Unknown YUV order: ") + eglu::getYuvOrderStr(order).toString()).c_str()); } } static int getYuvPlaneBppValue (EGLenum bpp) { switch (bpp) { case EGL_YUV_PLANE_BPP_0_EXT: return 0; case EGL_YUV_PLANE_BPP_8_EXT: return 8; case EGL_YUV_PLANE_BPP_10_EXT: return 10; default: TCU_THROW(TestError, (std::string("Unknown YUV plane BPP: ") + eglu::getYuvPlaneBppStr(bpp).toString()).c_str()); } } static int getColorComponentTypeRank (EGLenum compType) { switch (compType) { case EGL_COLOR_COMPONENT_TYPE_FIXED_EXT: return 0; case EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT: return 1; default: TCU_THROW(TestError, (std::string("Unknown color component type: ") + eglu::getColorComponentTypeStr(compType).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 compareYuvOrder (const SurfaceConfig& a, const SurfaceConfig& b) { return getYuvOrderRank((EGLenum)a.m_info.yuvOrder) < getYuvOrderRank((EGLenum)b.m_info.yuvOrder); } static bool compareColorComponentType (const SurfaceConfig& a, const SurfaceConfig& b) { return getColorComponentTypeRank((EGLenum)a.m_info.colorComponentType) < getColorComponentTypeRank((EGLenum)b.m_info.colorComponentType); } static bool compareColorBufferBits (const SurfaceConfig& a, const SurfaceConfig& b, const tcu::BVec4& specifiedRGBColors, const tcu::BVec2& specifiedLuminanceColors, bool yuvPlaneBppSpecified) { 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()); 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()); 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: return yuvPlaneBppSpecified ? (a.m_info.yuvPlaneBpp > b.m_info.yuvPlaneBpp) : false; default: DE_ASSERT(DE_FALSE); return true; } } template 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) { const std::map defaultRules = getDefaultRules(); for (std::map::const_iterator iter = defaultRules.begin(); iter != 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, bool yuvPlaneBppSpecified) const { static const SurfaceConfig::CompareFunc compareFuncs[] = { SurfaceConfig::compareCaveat, SurfaceConfig::compareColorComponentType, SurfaceConfig::compareColorBufferType, DE_NULL, // SurfaceConfig::compareColorBufferBits, SurfaceConfig::compareAttributeSmaller, SurfaceConfig::compareAttributeSmaller, SurfaceConfig::compareAttributeSmaller, SurfaceConfig::compareAttributeSmaller, SurfaceConfig::compareAttributeSmaller, SurfaceConfig::compareAttributeSmaller, SurfaceConfig::compareYuvOrder, SurfaceConfig::compareAttributeSmaller }; 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, yuvPlaneBppSpecified)) return true; else if (compareColorBufferBits(b, *this, specifiedRGBColors, specifiedLuminanceColors, yuvPlaneBppSpecified)) 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 std::map getDefaultRules (void) { // \todo [2011-03-24 pyry] From EGL 1.4 spec - check that this is valid for other versions as well std::map 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_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); // EGL_EXT_yuv_surface rules[EGL_YUV_ORDER_EXT] = AttribRule(EGL_YUV_ORDER_EXT, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_SPECIAL); rules[EGL_YUV_NUMBER_OF_PLANES_EXT] = AttribRule(EGL_YUV_NUMBER_OF_PLANES_EXT, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); rules[EGL_YUV_SUBSAMPLE_EXT] = AttribRule(EGL_YUV_SUBSAMPLE_EXT, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); rules[EGL_YUV_DEPTH_RANGE_EXT] = AttribRule(EGL_YUV_DEPTH_RANGE_EXT, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); rules[EGL_YUV_CSC_STANDARD_EXT] = AttribRule(EGL_YUV_CSC_STANDARD_EXT, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); rules[EGL_YUV_PLANE_BPP_EXT] = AttribRule(EGL_YUV_PLANE_BPP_EXT, EGL_DONT_CARE, CRITERIA_AT_LEAST, SORTORDER_SPECIAL); // 3 // EGL_EXT_pixel_format_float rules[EGL_COLOR_COMPONENT_TYPE_EXT] = AttribRule(EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT, CRITERIA_EXACT, SORTORDER_SPECIAL); // 2 return rules; } private: EGLConfig m_config; ConfigInfo m_info; }; class CompareConfigs { public: CompareConfigs (const tcu::BVec4& specifiedRGBColors, const tcu::BVec2& specifiedLuminanceColors, bool yuvPlaneBppSpecified) : m_specifiedRGBColors (specifiedRGBColors) , m_specifiedLuminanceColors (specifiedLuminanceColors) , m_yuvPlaneBppSpecified (yuvPlaneBppSpecified) { } bool operator() (const SurfaceConfig& a, const SurfaceConfig& b) { return a.compareTo(b, m_specifiedRGBColors, m_specifiedLuminanceColors, m_yuvPlaneBppSpecified); } private: const tcu::BVec4 m_specifiedRGBColors; const tcu::BVec2 m_specifiedLuminanceColors; const bool m_yuvPlaneBppSpecified; }; class ConfigFilter { private: std::map m_rules; public: ConfigFilter () : m_rules(SurfaceConfig::getDefaultRules()) { } void setValue (EGLenum name, EGLint value) { DE_ASSERT(de::contains(m_rules, name)); m_rules[name].value = value; } void setValues (std::vector > 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) const { DE_ASSERT(de::contains(m_rules, name)); return m_rules.find(name)->second; } bool isMatch (const SurfaceConfig& config) const { bool match = true; for (std::map::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); if (rule.name == EGL_CONFIG_ID) return (rule.value == cfgValue); switch (rule.criteria) { case CRITERIA_EXACT: if (rule.value != cfgValue) match = false; break; case CRITERIA_AT_LEAST: if (rule.value > cfgValue) match = false; break; case CRITERIA_MASK: if ((rule.value & cfgValue) != rule.value) match = false; break; default: TCU_FAIL("Unknown criteria"); } } } return match; } tcu::BVec4 getSpecifiedRGBColors (void) const { 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 { 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; } bool isYuvPlaneBppSpecified (void) const { const EGLenum attrib = EGL_YUV_PLANE_BPP_EXT; const EGLint value = getAttribute(attrib).value; return (value != 0) && (value != EGL_DONT_CARE); } std::vector filter (const std::vector& configs) const { std::vector out; for (std::vector::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& dst, const std::vector >& attributes) { // Get all configs std::vector eglConfigs = eglu::getConfigs(egl, display); // Config infos - including extension attributes std::vector configInfos; configInfos.resize(eglConfigs.size()); for (size_t ndx = 0; ndx < eglConfigs.size(); ndx++) { eglu::queryCoreConfigInfo(egl, display, eglConfigs[ndx], &configInfos[ndx]); eglu::queryExtConfigInfo(egl, display, eglConfigs[ndx], &configInfos[ndx]); } // Pair configs with info std::vector 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 filteredConfigs = configFilter.filter(configs); // Sort configs std::sort(filteredConfigs.begin(), filteredConfigs.end(), CompareConfigs(configFilter.getSpecifiedRGBColors(), configFilter.getSpecifiedLuminanceColors(), configFilter.isYuvPlaneBppSpecified())); // Write to dst list dst.resize(filteredConfigs.size()); for (size_t ndx = 0; ndx < filteredConfigs.size(); ndx++) dst[ndx] = filteredConfigs[ndx].getEglConfig(); } } // egl } // deqp