Rewrite ConfigSet and make EGLConfig synonymous with egl::Config.

BUG=angle:658

Change-Id: I3c33faf18af0bfda00dc5babe6356d6c8661f032
Reviewed-on: https://chromium-review.googlesource.com/238862
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Reviewed-by: Brandon Jones <bajones@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tested-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/Config.cpp b/src/libANGLE/Config.cpp
index 6e59db7..68d1b08 100644
--- a/src/libANGLE/Config.cpp
+++ b/src/libANGLE/Config.cpp
@@ -6,9 +6,10 @@
 
 // Config.cpp: Implements the egl::Config class, describing the format, type
 // and size for an egl::Surface. Implements EGLConfig and related functionality.
-// [EGL 1.4] section 3.4 page 15.
+// [EGL 1.5] section 3.4 page 19.
 
 #include "libANGLE/Config.h"
+#include "libANGLE/AttributeMap.h"
 
 #include <algorithm>
 #include <vector>
@@ -18,10 +19,13 @@
 
 #include "common/debug.h"
 
-using namespace std;
-
 namespace egl
 {
+
+Config::Config()
+{
+}
+
 Config::Config(rx::ConfigDesc desc, EGLint minInterval, EGLint maxInterval, EGLint texWidth, EGLint texHeight)
     : mRenderTargetFormat(desc.renderTargetFormat), mDepthStencilFormat(desc.depthStencilFormat), mMultiSample(desc.multiSample)
 {
@@ -142,217 +146,209 @@
     }
 }
 
-EGLConfig Config::getHandle() const
+EGLint ConfigSet::add(const Config &config)
 {
-    return (EGLConfig)(size_t)mConfigID;
+    // Set the config's ID to a small number that starts at 1 ([EGL 1.5] section 3.4)
+    EGLint id = mConfigs.size() + 1;
+
+    Config copyConfig(config);
+    copyConfig.mConfigID = id;
+    mConfigs.insert(std::make_pair(id, copyConfig));
+
+    return id;
 }
 
-SortConfig::SortConfig(const EGLint *attribList)
-    : mWantRed(false), mWantGreen(false), mWantBlue(false), mWantAlpha(false), mWantLuminance(false)
+const Config &ConfigSet::get(EGLint id) const
 {
-    scanForWantedComponents(attribList);
+    return mConfigs.at(id);
 }
 
-void SortConfig::scanForWantedComponents(const EGLint *attribList)
+void ConfigSet::clear()
 {
-    // [EGL] section 3.4.1 page 24
-    // Sorting rule #3: by larger total number of color bits, not considering
-    // components that are 0 or don't-care.
-    for (const EGLint *attr = attribList; attr[0] != EGL_NONE; attr += 2)
-    {
-        if (attr[1] != 0 && attr[1] != EGL_DONT_CARE)
-        {
-            switch (attr[0])
-            {
-              case EGL_RED_SIZE:       mWantRed = true; break;
-              case EGL_GREEN_SIZE:     mWantGreen = true; break;
-              case EGL_BLUE_SIZE:      mWantBlue = true; break;
-              case EGL_ALPHA_SIZE:     mWantAlpha = true; break;
-              case EGL_LUMINANCE_SIZE: mWantLuminance = true; break;
-            }
-        }
-    }
-}
-
-EGLint SortConfig::wantedComponentsSize(const Config &config) const
-{
-    EGLint total = 0;
-
-    if (mWantRed)       total += config.mRedSize;
-    if (mWantGreen)     total += config.mGreenSize;
-    if (mWantBlue)      total += config.mBlueSize;
-    if (mWantAlpha)     total += config.mAlphaSize;
-    if (mWantLuminance) total += config.mLuminanceSize;
-
-    return total;
-}
-
-bool SortConfig::operator()(const Config *x, const Config *y) const
-{
-    return (*this)(*x, *y);
-}
-
-bool SortConfig::operator()(const Config &x, const Config &y) const
-{
-    #define SORT(attribute)                        \
-        if (x.attribute != y.attribute)            \
-        {                                          \
-            return x.attribute < y.attribute;      \
-        }
-
-    META_ASSERT(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
-    SORT(mConfigCaveat);
-
-    META_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
-    SORT(mColorBufferType);
-
-    // 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(mBufferSize);
-    SORT(mSampleBuffers);
-    SORT(mSamples);
-    SORT(mDepthSize);
-    SORT(mStencilSize);
-    SORT(mAlphaMaskSize);
-    SORT(mNativeVisualType);
-    SORT(mConfigID);
-
-    #undef SORT
-
-    return false;
-}
-
-// We'd like to use SortConfig to also eliminate duplicate configs.
-// This works as long as we never have two configs with different per-RGB-component layouts,
-// but the same total.
-// 5551 and 565 are different because R+G+B is different.
-// 5551 and 555 are different because bufferSize is different.
-const EGLint ConfigSet::mSortAttribs[] =
-{
-    EGL_RED_SIZE, 1,
-    EGL_GREEN_SIZE, 1,
-    EGL_BLUE_SIZE, 1,
-    EGL_LUMINANCE_SIZE, 1,
-    // BUT NOT ALPHA
-    EGL_NONE
-};
-
-ConfigSet::ConfigSet()
-    : mSet(SortConfig(mSortAttribs))
-{
-}
-
-void ConfigSet::add(rx::ConfigDesc desc, EGLint minSwapInterval, EGLint maxSwapInterval, EGLint texWidth, EGLint texHeight)
-{
-    Config config(desc, minSwapInterval, maxSwapInterval, texWidth, texHeight);
-    mSet.insert(config);
+    mConfigs.clear();
 }
 
 size_t ConfigSet::size() const
 {
-    return mSet.size();
+    return mConfigs.size();
 }
 
-bool ConfigSet::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
+bool ConfigSet::contains(const Config *config) const
 {
-    vector<const Config*> passed;
-    passed.reserve(mSet.size());
-
-    for (Iterator config = mSet.begin(); config != mSet.end(); config++)
+    for (auto i = mConfigs.begin(); i != mConfigs.end(); i++)
     {
-        bool match = true;
-        const EGLint *attribute = attribList;
-
-        while (attribute[0] != EGL_NONE)
+        const Config &item = i->second;
+        if (config == &item)
         {
-            switch (attribute[0])
+            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)
+    {
+        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)                        \
+            if (x.attribute != y.attribute)            \
+            {                                          \
+                return x.attribute < y.attribute;      \
+            }
+
+        META_ASSERT(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
+        SORT(mConfigCaveat);
+
+        META_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
+        SORT(mColorBufferType);
+
+        // 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(mBufferSize);
+        SORT(mSampleBuffers);
+        SORT(mSamples);
+        SORT(mDepthSize);
+        SORT(mStencilSize);
+        SORT(mAlphaMaskSize);
+        SORT(mNativeVisualType);
+        SORT(mConfigID);
+
+        #undef SORT
+
+        return false;
+    }
+
+  private:
+    void scanForWantedComponents(const AttributeMap &attributeMap)
+    {
+        // [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.
+        for (auto attribIter = attributeMap.begin(); attribIter != attributeMap.end(); attribIter++)
+        {
+            EGLint attributeKey = attribIter->first;
+            EGLint attributeValue = attribIter->second;
+            if (attributeKey != 0 && attributeValue != EGL_DONT_CARE)
             {
-              case EGL_BUFFER_SIZE:               match = config->mBufferSize >= attribute[1];                      break;
-              case EGL_ALPHA_SIZE:                match = config->mAlphaSize >= attribute[1];                       break;
-              case EGL_BLUE_SIZE:                 match = config->mBlueSize >= attribute[1];                        break;
-              case EGL_GREEN_SIZE:                match = config->mGreenSize >= attribute[1];                       break;
-              case EGL_RED_SIZE:                  match = config->mRedSize >= attribute[1];                         break;
-              case EGL_DEPTH_SIZE:                match = config->mDepthSize >= attribute[1];                       break;
-              case EGL_STENCIL_SIZE:              match = config->mStencilSize >= attribute[1];                     break;
-              case EGL_CONFIG_CAVEAT:             match = config->mConfigCaveat == (EGLenum) attribute[1];          break;
-              case EGL_CONFIG_ID:                 match = config->mConfigID == attribute[1];                        break;
-              case EGL_LEVEL:                     match = config->mLevel >= attribute[1];                           break;
-              case EGL_NATIVE_RENDERABLE:         match = config->mNativeRenderable == (EGLBoolean) attribute[1];   break;
-              case EGL_NATIVE_VISUAL_TYPE:        match = config->mNativeVisualType == attribute[1];                break;
-              case EGL_SAMPLES:                   match = config->mSamples >= attribute[1];                         break;
-              case EGL_SAMPLE_BUFFERS:            match = config->mSampleBuffers >= attribute[1];                   break;
-              case EGL_SURFACE_TYPE:              match = (config->mSurfaceType & attribute[1]) == attribute[1];    break;
-              case EGL_TRANSPARENT_TYPE:          match = config->mTransparentType == (EGLenum) attribute[1];       break;
-              case EGL_TRANSPARENT_BLUE_VALUE:    match = config->mTransparentBlueValue == attribute[1];            break;
-              case EGL_TRANSPARENT_GREEN_VALUE:   match = config->mTransparentGreenValue == attribute[1];           break;
-              case EGL_TRANSPARENT_RED_VALUE:     match = config->mTransparentRedValue == attribute[1];             break;
-              case EGL_BIND_TO_TEXTURE_RGB:       match = config->mBindToTextureRGB == (EGLBoolean) attribute[1];   break;
-              case EGL_BIND_TO_TEXTURE_RGBA:      match = config->mBindToTextureRGBA == (EGLBoolean) attribute[1];  break;
-              case EGL_MIN_SWAP_INTERVAL:         match = config->mMinSwapInterval == attribute[1];                 break;
-              case EGL_MAX_SWAP_INTERVAL:         match = config->mMaxSwapInterval == attribute[1];                 break;
-              case EGL_LUMINANCE_SIZE:            match = config->mLuminanceSize >= attribute[1];                   break;
-              case EGL_ALPHA_MASK_SIZE:           match = config->mAlphaMaskSize >= attribute[1];                   break;
-              case EGL_COLOR_BUFFER_TYPE:         match = config->mColorBufferType == (EGLenum) attribute[1];       break;
-              case EGL_RENDERABLE_TYPE:           match = (config->mRenderableType & attribute[1]) == attribute[1]; break;
-              case EGL_MATCH_NATIVE_PIXMAP:       match = false; UNIMPLEMENTED();                                   break;
-              case EGL_CONFORMANT:                match = (config->mConformant & attribute[1]) == attribute[1];     break;
-              case EGL_MAX_PBUFFER_WIDTH:         match = config->mMaxPBufferWidth >= attribute[1];                 break;
-              case EGL_MAX_PBUFFER_HEIGHT:        match = config->mMaxPBufferHeight >= attribute[1];                break;
-              case EGL_MAX_PBUFFER_PIXELS:        match = config->mMaxPBufferPixels >= attribute[1];                break;
-              default:
-                return false;
+                switch (attributeKey)
+                {
+                case EGL_RED_SIZE:       mWantRed = true; break;
+                case EGL_GREEN_SIZE:     mWantGreen = true; break;
+                case EGL_BLUE_SIZE:      mWantBlue = true; break;
+                case EGL_ALPHA_SIZE:     mWantAlpha = true; break;
+                case EGL_LUMINANCE_SIZE: mWantLuminance = true; break;
+                }
+            }
+        }
+    }
+
+    EGLint wantedComponentsSize(const Config &config) const
+    {
+        EGLint total = 0;
+
+        if (mWantRed)       total += config.mRedSize;
+        if (mWantGreen)     total += config.mGreenSize;
+        if (mWantBlue)      total += config.mBlueSize;
+        if (mWantAlpha)     total += config.mAlphaSize;
+        if (mWantLuminance) total += config.mLuminanceSize;
+
+        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++)
+        {
+            EGLint attributeKey = attribIter->first;
+            EGLint attributeValue = attribIter->second;
+
+            switch (attributeKey)
+            {
+              case EGL_BUFFER_SIZE:               match = config.mBufferSize >= attributeValue;                        break;
+              case EGL_ALPHA_SIZE:                match = config.mAlphaSize >= attributeValue;                         break;
+              case EGL_BLUE_SIZE:                 match = config.mBlueSize >= attributeValue;                          break;
+              case EGL_GREEN_SIZE:                match = config.mGreenSize >= attributeValue;                         break;
+              case EGL_RED_SIZE:                  match = config.mRedSize >= attributeValue;                           break;
+              case EGL_DEPTH_SIZE:                match = config.mDepthSize >= attributeValue;                         break;
+              case EGL_STENCIL_SIZE:              match = config.mStencilSize >= attributeValue;                       break;
+              case EGL_CONFIG_CAVEAT:             match = config.mConfigCaveat == (EGLenum)attributeValue;             break;
+              case EGL_CONFIG_ID:                 match = config.mConfigID == attributeValue;                          break;
+              case EGL_LEVEL:                     match = config.mLevel >= attributeValue;                             break;
+              case EGL_NATIVE_RENDERABLE:         match = config.mNativeRenderable == (EGLBoolean)attributeValue;      break;
+              case EGL_NATIVE_VISUAL_TYPE:        match = config.mNativeVisualType == attributeValue;                  break;
+              case EGL_SAMPLES:                   match = config.mSamples >= attributeValue;                           break;
+              case EGL_SAMPLE_BUFFERS:            match = config.mSampleBuffers >= attributeValue;                     break;
+              case EGL_SURFACE_TYPE:              match = (config.mSurfaceType & attributeValue) == attributeValue;    break;
+              case EGL_TRANSPARENT_TYPE:          match = config.mTransparentType == (EGLenum)attributeValue;          break;
+              case EGL_TRANSPARENT_BLUE_VALUE:    match = config.mTransparentBlueValue == attributeValue;              break;
+              case EGL_TRANSPARENT_GREEN_VALUE:   match = config.mTransparentGreenValue == attributeValue;             break;
+              case EGL_TRANSPARENT_RED_VALUE:     match = config.mTransparentRedValue == attributeValue;               break;
+              case EGL_BIND_TO_TEXTURE_RGB:       match = config.mBindToTextureRGB == (EGLBoolean)attributeValue;      break;
+              case EGL_BIND_TO_TEXTURE_RGBA:      match = config.mBindToTextureRGBA == (EGLBoolean)attributeValue;     break;
+              case EGL_MIN_SWAP_INTERVAL:         match = config.mMinSwapInterval == attributeValue;                   break;
+              case EGL_MAX_SWAP_INTERVAL:         match = config.mMaxSwapInterval == attributeValue;                   break;
+              case EGL_LUMINANCE_SIZE:            match = config.mLuminanceSize >= attributeValue;                     break;
+              case EGL_ALPHA_MASK_SIZE:           match = config.mAlphaMaskSize >= attributeValue;                     break;
+              case EGL_COLOR_BUFFER_TYPE:         match = config.mColorBufferType == (EGLenum)attributeValue;          break;
+              case EGL_RENDERABLE_TYPE:           match = (config.mRenderableType & attributeValue) == attributeValue; break;
+              case EGL_MATCH_NATIVE_PIXMAP:       match = false; UNIMPLEMENTED();                                      break;
+              case EGL_CONFORMANT:                match = (config.mConformant & attributeValue) == attributeValue;     break;
+              case EGL_MAX_PBUFFER_WIDTH:         match = config.mMaxPBufferWidth >= attributeValue;                   break;
+              case EGL_MAX_PBUFFER_HEIGHT:        match = config.mMaxPBufferHeight >= attributeValue;                  break;
+              case EGL_MAX_PBUFFER_PIXELS:        match = config.mMaxPBufferPixels >= attributeValue;                  break;
+              default: UNREACHABLE();
             }
 
             if (!match)
             {
                 break;
             }
-
-            attribute += 2;
         }
 
         if (match)
         {
-            passed.push_back(&*config);
+            result.push_back(&config);
         }
     }
 
-    if (configs)
-    {
-        sort(passed.begin(), passed.end(), SortConfig(attribList));
+    // Sort the result
+    std::sort(result.begin(), result.end(), ConfigSorter(attributeMap));
 
-        EGLint index;
-        for (index = 0; index < configSize && index < static_cast<EGLint>(passed.size()); index++)
-        {
-            configs[index] = passed[index]->getHandle();
-        }
-
-        *numConfig = index;
-    }
-    else
-    {
-        *numConfig = passed.size();
-    }
-
-    return true;
+    return result;
 }
 
-const egl::Config *ConfigSet::get(EGLConfig configHandle)
-{
-    for (Iterator config = mSet.begin(); config != mSet.end(); config++)
-    {
-        if (config->getHandle() == configHandle)
-        {
-            return &(*config);
-        }
-    }
-
-    return NULL;
-}
 }