1/*------------------------------------------------------------------------- 2 * drawElements Quality Program EGL Module 3 * --------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Choose config reference implementation. 22 *//*--------------------------------------------------------------------*/ 23 24#include "teglChooseConfigReference.hpp" 25 26#include "egluUtil.hpp" 27#include "egluConfigInfo.hpp" 28#include "egluStrUtil.hpp" 29#include "eglwLibrary.hpp" 30#include "eglwEnums.hpp" 31 32#include <algorithm> 33#include <vector> 34#include <map> 35 36namespace deqp 37{ 38namespace egl 39{ 40 41using namespace eglw; 42using eglu::ConfigInfo; 43 44enum Criteria 45{ 46 CRITERIA_AT_LEAST = 0, 47 CRITERIA_EXACT, 48 CRITERIA_MASK, 49 CRITERIA_SPECIAL, 50 51 CRITERIA_LAST 52}; 53 54enum SortOrder 55{ 56 SORTORDER_NONE = 0, 57 SORTORDER_SMALLER, 58 SORTORDER_SPECIAL, 59 60 SORTORDER_LAST 61}; 62 63struct AttribRule 64{ 65 EGLenum name; 66 EGLint value; 67 Criteria criteria; 68 SortOrder sortOrder; 69 70 AttribRule (void) 71 : name (EGL_NONE) 72 , value (EGL_NONE) 73 , criteria (CRITERIA_LAST) 74 , sortOrder (SORTORDER_LAST) 75 { 76 } 77 78 AttribRule (EGLenum name_, EGLint value_, Criteria criteria_, SortOrder sortOrder_) 79 : name (name_) 80 , value (value_) 81 , criteria (criteria_) 82 , sortOrder (sortOrder_) 83 { 84 } 85}; 86 87class SurfaceConfig 88{ 89private: 90 static int getCaveatRank (EGLenum caveat) 91 { 92 switch (caveat) 93 { 94 case EGL_NONE: return 0; 95 case EGL_SLOW_CONFIG: return 1; 96 case EGL_NON_CONFORMANT_CONFIG: return 2; 97 default: 98 TCU_THROW(TestError, (std::string("Unknown config caveat: ") + eglu::getConfigCaveatStr(caveat).toString()).c_str()); 99 } 100 } 101 102 static int getColorBufferTypeRank (EGLenum type) 103 { 104 switch (type) 105 { 106 case EGL_RGB_BUFFER: return 0; 107 case EGL_LUMINANCE_BUFFER: return 1; 108 case EGL_YUV_BUFFER_EXT: return 2; 109 default: 110 TCU_THROW(TestError, (std::string("Unknown color buffer type: ") + eglu::getColorBufferTypeStr(type).toString()).c_str()); 111 } 112 } 113 114 typedef bool (*CompareFunc) (const SurfaceConfig& a, const SurfaceConfig& b); 115 116 static bool compareCaveat (const SurfaceConfig& a, const SurfaceConfig& b) 117 { 118 return getCaveatRank((EGLenum)a.m_info.configCaveat) < getCaveatRank((EGLenum)b.m_info.configCaveat); 119 } 120 121 static bool compareColorBufferType (const SurfaceConfig& a, const SurfaceConfig& b) 122 { 123 return getColorBufferTypeRank((EGLenum)a.m_info.colorBufferType) < getColorBufferTypeRank((EGLenum)b.m_info.colorBufferType); 124 } 125 126 static bool compareColorBufferBits (const SurfaceConfig& a, const SurfaceConfig& b, const tcu::BVec4& specifiedRGBColors, const tcu::BVec2& specifiedLuminanceColors) 127 { 128 DE_ASSERT(a.m_info.colorBufferType == b.m_info.colorBufferType); 129 switch (a.m_info.colorBufferType) 130 { 131 case EGL_RGB_BUFFER: 132 { 133 const tcu::IVec4 mask (specifiedRGBColors.cast<deInt32>()); 134 135 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]) 136 > (b.m_info.redSize * mask[0] + b.m_info.greenSize * mask[1] + b.m_info.blueSize * mask[2] + b.m_info.alphaSize * mask[3]); 137 } 138 139 case EGL_LUMINANCE_BUFFER: 140 { 141 const tcu::IVec2 mask (specifiedLuminanceColors.cast<deInt32>()); 142 143 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]); 144 } 145 146 case EGL_YUV_BUFFER_EXT: 147 // \todo [mika 2015-05-05] Sort YUV configs correctly. Currently all YUV configs are non-conformant and ordering can be relaxed. 148 return true; 149 150 default: 151 DE_ASSERT(DE_FALSE); 152 return true; 153 } 154 } 155 156 template <EGLenum Attribute> 157 static bool compareAttributeSmaller (const SurfaceConfig& a, const SurfaceConfig& b) 158 { 159 return a.getAttribute(Attribute) < b.getAttribute(Attribute); 160 } 161public: 162 SurfaceConfig (EGLConfig config, ConfigInfo &info) 163 : m_config(config) 164 , m_info(info) 165 { 166 } 167 168 EGLConfig getEglConfig (void) const 169 { 170 return m_config; 171 } 172 173 EGLint getAttribute (const EGLenum attribute) const 174 { 175 return m_info.getAttribute(attribute); 176 } 177 178 friend bool operator== (const SurfaceConfig& a, const SurfaceConfig& b) 179 { 180 for (std::map<EGLenum, AttribRule>::const_iterator iter = SurfaceConfig::defaultRules.begin(); iter != SurfaceConfig::defaultRules.end(); iter++) 181 { 182 const EGLenum attribute = iter->first; 183 184 if (a.getAttribute(attribute) != b.getAttribute(attribute)) return false; 185 } 186 return true; 187 } 188 189 bool compareTo (const SurfaceConfig& b, const tcu::BVec4& specifiedRGBColors, const tcu::BVec2& specifiedLuminanceColors) const 190 { 191 static const SurfaceConfig::CompareFunc compareFuncs[] = 192 { 193 SurfaceConfig::compareCaveat, 194 SurfaceConfig::compareColorBufferType, 195 DE_NULL, // SurfaceConfig::compareColorBufferBits, 196 SurfaceConfig::compareAttributeSmaller<EGL_BUFFER_SIZE>, 197 SurfaceConfig::compareAttributeSmaller<EGL_SAMPLE_BUFFERS>, 198 SurfaceConfig::compareAttributeSmaller<EGL_SAMPLES>, 199 SurfaceConfig::compareAttributeSmaller<EGL_DEPTH_SIZE>, 200 SurfaceConfig::compareAttributeSmaller<EGL_STENCIL_SIZE>, 201 SurfaceConfig::compareAttributeSmaller<EGL_ALPHA_MASK_SIZE>, 202 SurfaceConfig::compareAttributeSmaller<EGL_CONFIG_ID> 203 }; 204 205 if (*this == b) 206 return false; // std::sort() can compare object to itself. 207 208 for (int ndx = 0; ndx < (int)DE_LENGTH_OF_ARRAY(compareFuncs); ndx++) 209 { 210 if (!compareFuncs[ndx]) 211 { 212 if (compareColorBufferBits(*this, b, specifiedRGBColors, specifiedLuminanceColors)) 213 return true; 214 else if (compareColorBufferBits(b, *this, specifiedRGBColors, specifiedLuminanceColors)) 215 return false; 216 217 continue; 218 } 219 220 if (compareFuncs[ndx](*this, b)) 221 return true; 222 else if (compareFuncs[ndx](b, *this)) 223 return false; 224 } 225 226 TCU_FAIL("Unable to compare configs - duplicate ID?"); 227 } 228 229 static const std::map<EGLenum, AttribRule> defaultRules; 230 231 static std::map<EGLenum, AttribRule> initAttribRules (void) 232 { 233 // \todo [2011-03-24 pyry] From EGL 1.4 spec - check that this is valid for other versions as well 234 std::map<EGLenum, AttribRule> rules; 235 236 // Attribute Default Selection Criteria Sort Order Sort Priority 237 rules[EGL_BUFFER_SIZE] = AttribRule(EGL_BUFFER_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SMALLER); // 4 238 rules[EGL_RED_SIZE] = AttribRule(EGL_RED_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SPECIAL); // 3 239 rules[EGL_GREEN_SIZE] = AttribRule(EGL_GREEN_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SPECIAL); // 3 240 rules[EGL_BLUE_SIZE] = AttribRule(EGL_BLUE_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SPECIAL); // 3 241 rules[EGL_LUMINANCE_SIZE] = AttribRule(EGL_LUMINANCE_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SPECIAL); // 3 242 rules[EGL_ALPHA_SIZE] = AttribRule(EGL_ALPHA_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SPECIAL); // 3 243 rules[EGL_ALPHA_MASK_SIZE] = AttribRule(EGL_ALPHA_MASK_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SMALLER); // 9 244 rules[EGL_BIND_TO_TEXTURE_RGB] = AttribRule(EGL_BIND_TO_TEXTURE_RGB, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); 245 rules[EGL_BIND_TO_TEXTURE_RGBA] = AttribRule(EGL_BIND_TO_TEXTURE_RGBA, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); 246 rules[EGL_COLOR_BUFFER_TYPE] = AttribRule(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, CRITERIA_EXACT, SORTORDER_NONE); // 2 247 rules[EGL_CONFIG_CAVEAT] = AttribRule(EGL_CONFIG_CAVEAT, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_SPECIAL); // 1 248 rules[EGL_CONFIG_ID] = AttribRule(EGL_CONFIG_ID, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_SMALLER); // 11 249 rules[EGL_CONFORMANT] = AttribRule(EGL_CONFORMANT, 0, CRITERIA_MASK, SORTORDER_NONE); 250 rules[EGL_DEPTH_SIZE] = AttribRule(EGL_DEPTH_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SMALLER); // 7 251 rules[EGL_LEVEL] = AttribRule(EGL_LEVEL, 0, CRITERIA_EXACT, SORTORDER_NONE); 252 rules[EGL_MATCH_NATIVE_PIXMAP] = AttribRule(EGL_MATCH_NATIVE_PIXMAP, EGL_NONE, CRITERIA_SPECIAL, SORTORDER_NONE); 253 rules[EGL_MAX_SWAP_INTERVAL] = AttribRule(EGL_MAX_SWAP_INTERVAL, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); 254 rules[EGL_MIN_SWAP_INTERVAL] = AttribRule(EGL_MIN_SWAP_INTERVAL, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); 255 rules[EGL_NATIVE_RENDERABLE] = AttribRule(EGL_NATIVE_RENDERABLE, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); 256 rules[EGL_NATIVE_VISUAL_TYPE] = AttribRule(EGL_NATIVE_VISUAL_TYPE, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_SPECIAL); // 10 257 rules[EGL_RENDERABLE_TYPE] = AttribRule(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT, CRITERIA_MASK, SORTORDER_NONE); 258 rules[EGL_SAMPLE_BUFFERS] = AttribRule(EGL_SAMPLE_BUFFERS, 0, CRITERIA_AT_LEAST, SORTORDER_SMALLER); // 5 259 rules[EGL_SAMPLES] = AttribRule(EGL_SAMPLES, 0, CRITERIA_AT_LEAST, SORTORDER_SMALLER); // 6 260 rules[EGL_STENCIL_SIZE] = AttribRule(EGL_STENCIL_SIZE, 0, CRITERIA_AT_LEAST, SORTORDER_SMALLER); // 8 261 rules[EGL_SURFACE_TYPE] = AttribRule(EGL_SURFACE_TYPE, EGL_WINDOW_BIT, CRITERIA_MASK, SORTORDER_NONE); 262 rules[EGL_TRANSPARENT_TYPE] = AttribRule(EGL_TRANSPARENT_TYPE, EGL_NONE, CRITERIA_EXACT, SORTORDER_NONE); 263 rules[EGL_TRANSPARENT_RED_VALUE] = AttribRule(EGL_TRANSPARENT_RED_VALUE, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); 264 rules[EGL_TRANSPARENT_GREEN_VALUE] = AttribRule(EGL_TRANSPARENT_GREEN_VALUE, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); 265 rules[EGL_TRANSPARENT_BLUE_VALUE] = AttribRule(EGL_TRANSPARENT_BLUE_VALUE, EGL_DONT_CARE, CRITERIA_EXACT, SORTORDER_NONE); 266 267 return rules; 268 } 269private: 270 EGLConfig m_config; 271 ConfigInfo m_info; 272}; 273 274const std::map<EGLenum, AttribRule> SurfaceConfig::defaultRules = SurfaceConfig::initAttribRules(); 275 276class CompareConfigs 277{ 278public: 279 CompareConfigs (const tcu::BVec4& specifiedRGBColors, const tcu::BVec2& specifiedLuminanceColors) 280 : m_specifiedRGBColors (specifiedRGBColors) 281 , m_specifiedLuminanceColors (specifiedLuminanceColors) 282 { 283 } 284 285 bool operator() (const SurfaceConfig& a, const SurfaceConfig& b) 286 { 287 return a.compareTo(b, m_specifiedRGBColors, m_specifiedLuminanceColors); 288 } 289 290private: 291 const tcu::BVec4 m_specifiedRGBColors; 292 const tcu::BVec2 m_specifiedLuminanceColors; 293}; 294 295class ConfigFilter 296{ 297private: 298 std::map<EGLenum, AttribRule> m_rules; 299public: 300 ConfigFilter () 301 : m_rules(SurfaceConfig::defaultRules) 302 { 303 } 304 305 void setValue (EGLenum name, EGLint value) 306 { 307 DE_ASSERT(SurfaceConfig::defaultRules.find(name) != SurfaceConfig::defaultRules.end()); 308 m_rules[name].value = value; 309 } 310 311 void setValues (std::vector<std::pair<EGLenum, EGLint> > values) 312 { 313 for (size_t ndx = 0; ndx < values.size(); ndx++) 314 { 315 const EGLenum name = values[ndx].first; 316 const EGLint value = values[ndx].second; 317 318 setValue(name, value); 319 } 320 } 321 322 AttribRule getAttribute (EGLenum name) 323 { 324 DE_ASSERT(SurfaceConfig::defaultRules.find(name) != SurfaceConfig::defaultRules.end()); 325 return m_rules[name]; 326 } 327 328 bool isMatch (const SurfaceConfig& config) 329 { 330 for (std::map<EGLenum, AttribRule>::const_iterator iter = m_rules.begin(); iter != m_rules.end(); iter++) 331 { 332 const AttribRule rule = iter->second; 333 334 if (rule.value == EGL_DONT_CARE) 335 continue; 336 else if (rule.name == EGL_MATCH_NATIVE_PIXMAP) 337 TCU_CHECK(rule.value == EGL_NONE); // Not supported 338 else if (rule.name == EGL_TRANSPARENT_RED_VALUE || rule.name == EGL_TRANSPARENT_GREEN_VALUE || rule.name == EGL_TRANSPARENT_BLUE_VALUE) 339 continue; 340 else 341 { 342 const EGLint cfgValue = config.getAttribute(rule.name); 343 344 switch (rule.criteria) 345 { 346 case CRITERIA_EXACT: 347 if (rule.value != cfgValue) 348 return false; 349 break; 350 351 case CRITERIA_AT_LEAST: 352 if (rule.value > cfgValue) 353 return false; 354 break; 355 356 case CRITERIA_MASK: 357 if ((rule.value & cfgValue) != rule.value) 358 return false; 359 break; 360 361 default: 362 TCU_FAIL("Unknown criteria"); 363 } 364 } 365 } 366 367 return true; 368 } 369 370 tcu::BVec4 getSpecifiedRGBColors (void) 371 { 372 const EGLenum bitAttribs[] = 373 { 374 EGL_RED_SIZE, 375 EGL_GREEN_SIZE, 376 EGL_BLUE_SIZE, 377 EGL_ALPHA_SIZE 378 }; 379 380 tcu::BVec4 result; 381 382 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(bitAttribs); ndx++) 383 { 384 const EGLenum attrib = bitAttribs[ndx]; 385 const EGLint value = getAttribute(attrib).value; 386 387 if (value != 0 && value != EGL_DONT_CARE) 388 result[ndx] = true; 389 else 390 result[ndx] = false; 391 } 392 393 return result; 394 } 395 396 tcu::BVec2 getSpecifiedLuminanceColors (void) 397 { 398 const EGLenum bitAttribs[] = 399 { 400 EGL_LUMINANCE_SIZE, 401 EGL_ALPHA_SIZE 402 }; 403 404 tcu::BVec2 result; 405 406 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(bitAttribs); ndx++) 407 { 408 const EGLenum attrib = bitAttribs[ndx]; 409 const EGLint value = getAttribute(attrib).value; 410 411 if (value != 0 && value != EGL_DONT_CARE) 412 result[ndx] = true; 413 else 414 result[ndx] = false; 415 } 416 417 return result; 418 } 419 420 std::vector<SurfaceConfig> filter (const std::vector<SurfaceConfig>& configs) 421 { 422 std::vector<SurfaceConfig> out; 423 424 for (std::vector<SurfaceConfig>::const_iterator iter = configs.begin(); iter != configs.end(); iter++) 425 { 426 if (isMatch(*iter)) out.push_back(*iter); 427 } 428 429 return out; 430 } 431}; 432 433void chooseConfigReference (const Library& egl, EGLDisplay display, std::vector<EGLConfig>& dst, const std::vector<std::pair<EGLenum, EGLint> >& attributes) 434{ 435 // Get all configs 436 std::vector<EGLConfig> eglConfigs = eglu::getConfigs(egl, display); 437 438 // Config infos 439 std::vector<ConfigInfo> configInfos; 440 configInfos.resize(eglConfigs.size()); 441 for (size_t ndx = 0; ndx < eglConfigs.size(); ndx++) 442 eglu::queryConfigInfo(egl, display, eglConfigs[ndx], &configInfos[ndx]); 443 444 // Pair configs with info 445 std::vector<SurfaceConfig> configs; 446 for (size_t ndx = 0; ndx < eglConfigs.size(); ndx++) 447 configs.push_back(SurfaceConfig(eglConfigs[ndx], configInfos[ndx])); 448 449 // Filter configs 450 ConfigFilter configFilter; 451 configFilter.setValues(attributes); 452 453 std::vector<SurfaceConfig> filteredConfigs = configFilter.filter(configs); 454 455 // Sort configs 456 std::sort(filteredConfigs.begin(), filteredConfigs.end(), CompareConfigs(configFilter.getSpecifiedRGBColors(), configFilter.getSpecifiedLuminanceColors())); 457 458 // Write to dst list 459 dst.resize(filteredConfigs.size()); 460 for (size_t ndx = 0; ndx < filteredConfigs.size(); ndx++) 461 dst[ndx] = filteredConfigs[ndx].getEglConfig(); 462} 463 464} // egl 465} // deqp 466