michael@0: // michael@0: // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: // michael@0: michael@0: // Config.cpp: Implements the egl::Config class, describing the format, type michael@0: // and size for an egl::Surface. Implements EGLConfig and related functionality. michael@0: // [EGL 1.4] section 3.4 page 15. michael@0: michael@0: #include "libEGL/Config.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "common/debug.h" michael@0: michael@0: using namespace std; michael@0: michael@0: namespace egl michael@0: { michael@0: Config::Config(rx::ConfigDesc desc, EGLint minInterval, EGLint maxInterval, EGLint texWidth, EGLint texHeight) michael@0: : mRenderTargetFormat(desc.renderTargetFormat), mDepthStencilFormat(desc.depthStencilFormat), mMultiSample(desc.multiSample) michael@0: { michael@0: mBindToTextureRGB = EGL_FALSE; michael@0: mBindToTextureRGBA = EGL_FALSE; michael@0: switch (desc.renderTargetFormat) michael@0: { michael@0: case GL_RGB5_A1: michael@0: mBufferSize = 16; michael@0: mRedSize = 5; michael@0: mGreenSize = 5; michael@0: mBlueSize = 5; michael@0: mAlphaSize = 1; michael@0: break; michael@0: case GL_RGBA8_OES: michael@0: mBufferSize = 32; michael@0: mRedSize = 8; michael@0: mGreenSize = 8; michael@0: mBlueSize = 8; michael@0: mAlphaSize = 8; michael@0: mBindToTextureRGBA = true; michael@0: break; michael@0: case GL_RGB565: michael@0: mBufferSize = 16; michael@0: mRedSize = 5; michael@0: mGreenSize = 6; michael@0: mBlueSize = 5; michael@0: mAlphaSize = 0; michael@0: break; michael@0: case GL_RGB8_OES: michael@0: mBufferSize = 32; michael@0: mRedSize = 8; michael@0: mGreenSize = 8; michael@0: mBlueSize = 8; michael@0: mAlphaSize = 0; michael@0: mBindToTextureRGB = true; michael@0: break; michael@0: case GL_BGRA8_EXT: michael@0: mBufferSize = 32; michael@0: mRedSize = 8; michael@0: mGreenSize = 8; michael@0: mBlueSize = 8; michael@0: mAlphaSize = 8; michael@0: mBindToTextureRGBA = true; michael@0: break; michael@0: default: michael@0: UNREACHABLE(); // Other formats should not be valid michael@0: } michael@0: michael@0: mLuminanceSize = 0; michael@0: mAlphaMaskSize = 0; michael@0: mColorBufferType = EGL_RGB_BUFFER; michael@0: mConfigCaveat = (desc.fastConfig) ? EGL_NONE : EGL_SLOW_CONFIG; michael@0: mConfigID = 0; michael@0: mConformant = EGL_OPENGL_ES2_BIT; michael@0: michael@0: switch (desc.depthStencilFormat) michael@0: { michael@0: case GL_NONE: michael@0: mDepthSize = 0; michael@0: mStencilSize = 0; michael@0: break; michael@0: case GL_DEPTH_COMPONENT32_OES: michael@0: mDepthSize = 32; michael@0: mStencilSize = 0; michael@0: break; michael@0: case GL_DEPTH24_STENCIL8_OES: michael@0: mDepthSize = 24; michael@0: mStencilSize = 8; michael@0: break; michael@0: case GL_DEPTH_COMPONENT24_OES: michael@0: mDepthSize = 24; michael@0: mStencilSize = 0; michael@0: break; michael@0: case GL_DEPTH_COMPONENT16: michael@0: mDepthSize = 16; michael@0: mStencilSize = 0; michael@0: break; michael@0: default: michael@0: UNREACHABLE(); michael@0: } michael@0: michael@0: mLevel = 0; michael@0: mMatchNativePixmap = EGL_NONE; michael@0: mMaxPBufferWidth = texWidth; michael@0: mMaxPBufferHeight = texHeight; michael@0: mMaxPBufferPixels = texWidth*texHeight; michael@0: mMaxSwapInterval = maxInterval; michael@0: mMinSwapInterval = minInterval; michael@0: mNativeRenderable = EGL_FALSE; michael@0: mNativeVisualID = 0; michael@0: mNativeVisualType = 0; michael@0: mRenderableType = EGL_OPENGL_ES2_BIT; michael@0: mSampleBuffers = desc.multiSample ? 1 : 0; michael@0: mSamples = desc.multiSample; michael@0: mSurfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT; michael@0: mTransparentType = EGL_NONE; michael@0: mTransparentRedValue = 0; michael@0: mTransparentGreenValue = 0; michael@0: mTransparentBlueValue = 0; michael@0: } michael@0: michael@0: EGLConfig Config::getHandle() const michael@0: { michael@0: return (EGLConfig)(size_t)mConfigID; michael@0: } michael@0: michael@0: SortConfig::SortConfig(const EGLint *attribList) michael@0: : mWantRed(false), mWantGreen(false), mWantBlue(false), mWantAlpha(false), mWantLuminance(false) michael@0: { michael@0: scanForWantedComponents(attribList); michael@0: } michael@0: michael@0: void SortConfig::scanForWantedComponents(const EGLint *attribList) michael@0: { michael@0: // [EGL] section 3.4.1 page 24 michael@0: // Sorting rule #3: by larger total number of color bits, not considering michael@0: // components that are 0 or don't-care. michael@0: for (const EGLint *attr = attribList; attr[0] != EGL_NONE; attr += 2) michael@0: { michael@0: if (attr[1] != 0 && attr[1] != EGL_DONT_CARE) michael@0: { michael@0: switch (attr[0]) michael@0: { michael@0: case EGL_RED_SIZE: mWantRed = true; break; michael@0: case EGL_GREEN_SIZE: mWantGreen = true; break; michael@0: case EGL_BLUE_SIZE: mWantBlue = true; break; michael@0: case EGL_ALPHA_SIZE: mWantAlpha = true; break; michael@0: case EGL_LUMINANCE_SIZE: mWantLuminance = true; break; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: EGLint SortConfig::wantedComponentsSize(const Config &config) const michael@0: { michael@0: EGLint total = 0; michael@0: michael@0: if (mWantRed) total += config.mRedSize; michael@0: if (mWantGreen) total += config.mGreenSize; michael@0: if (mWantBlue) total += config.mBlueSize; michael@0: if (mWantAlpha) total += config.mAlphaSize; michael@0: if (mWantLuminance) total += config.mLuminanceSize; michael@0: michael@0: return total; michael@0: } michael@0: michael@0: bool SortConfig::operator()(const Config *x, const Config *y) const michael@0: { michael@0: return (*this)(*x, *y); michael@0: } michael@0: michael@0: bool SortConfig::operator()(const Config &x, const Config &y) const michael@0: { michael@0: #define SORT(attribute) \ michael@0: if (x.attribute != y.attribute) \ michael@0: { \ michael@0: return x.attribute < y.attribute; \ michael@0: } michael@0: michael@0: META_ASSERT(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG); michael@0: SORT(mConfigCaveat); michael@0: michael@0: META_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER); michael@0: SORT(mColorBufferType); michael@0: michael@0: // By larger total number of color bits, only considering those that are requested to be > 0. michael@0: EGLint xComponentsSize = wantedComponentsSize(x); michael@0: EGLint yComponentsSize = wantedComponentsSize(y); michael@0: if (xComponentsSize != yComponentsSize) michael@0: { michael@0: return xComponentsSize > yComponentsSize; michael@0: } michael@0: michael@0: SORT(mBufferSize); michael@0: SORT(mSampleBuffers); michael@0: SORT(mSamples); michael@0: SORT(mDepthSize); michael@0: SORT(mStencilSize); michael@0: SORT(mAlphaMaskSize); michael@0: SORT(mNativeVisualType); michael@0: SORT(mConfigID); michael@0: michael@0: #undef SORT michael@0: michael@0: return false; michael@0: } michael@0: michael@0: // We'd like to use SortConfig to also eliminate duplicate configs. michael@0: // This works as long as we never have two configs with different per-RGB-component layouts, michael@0: // but the same total. michael@0: // 5551 and 565 are different because R+G+B is different. michael@0: // 5551 and 555 are different because bufferSize is different. michael@0: const EGLint ConfigSet::mSortAttribs[] = michael@0: { michael@0: EGL_RED_SIZE, 1, michael@0: EGL_GREEN_SIZE, 1, michael@0: EGL_BLUE_SIZE, 1, michael@0: EGL_LUMINANCE_SIZE, 1, michael@0: // BUT NOT ALPHA michael@0: EGL_NONE michael@0: }; michael@0: michael@0: ConfigSet::ConfigSet() michael@0: : mSet(SortConfig(mSortAttribs)) michael@0: { michael@0: } michael@0: michael@0: void ConfigSet::add(rx::ConfigDesc desc, EGLint minSwapInterval, EGLint maxSwapInterval, EGLint texWidth, EGLint texHeight) michael@0: { michael@0: Config config(desc, minSwapInterval, maxSwapInterval, texWidth, texHeight); michael@0: mSet.insert(config); michael@0: } michael@0: michael@0: size_t ConfigSet::size() const michael@0: { michael@0: return mSet.size(); michael@0: } michael@0: michael@0: bool ConfigSet::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig) michael@0: { michael@0: vector passed; michael@0: passed.reserve(mSet.size()); michael@0: michael@0: for (Iterator config = mSet.begin(); config != mSet.end(); config++) michael@0: { michael@0: bool match = true; michael@0: const EGLint *attribute = attribList; michael@0: michael@0: while (attribute[0] != EGL_NONE) michael@0: { michael@0: switch (attribute[0]) michael@0: { michael@0: case EGL_BUFFER_SIZE: match = config->mBufferSize >= attribute[1]; break; michael@0: case EGL_ALPHA_SIZE: match = config->mAlphaSize >= attribute[1]; break; michael@0: case EGL_BLUE_SIZE: match = config->mBlueSize >= attribute[1]; break; michael@0: case EGL_GREEN_SIZE: match = config->mGreenSize >= attribute[1]; break; michael@0: case EGL_RED_SIZE: match = config->mRedSize >= attribute[1]; break; michael@0: case EGL_DEPTH_SIZE: match = config->mDepthSize >= attribute[1]; break; michael@0: case EGL_STENCIL_SIZE: match = config->mStencilSize >= attribute[1]; break; michael@0: case EGL_CONFIG_CAVEAT: match = config->mConfigCaveat == (EGLenum) attribute[1]; break; michael@0: case EGL_CONFIG_ID: match = config->mConfigID == attribute[1]; break; michael@0: case EGL_LEVEL: match = config->mLevel >= attribute[1]; break; michael@0: case EGL_NATIVE_RENDERABLE: match = config->mNativeRenderable == (EGLBoolean) attribute[1]; break; michael@0: case EGL_NATIVE_VISUAL_TYPE: match = config->mNativeVisualType == attribute[1]; break; michael@0: case EGL_SAMPLES: match = config->mSamples >= attribute[1]; break; michael@0: case EGL_SAMPLE_BUFFERS: match = config->mSampleBuffers >= attribute[1]; break; michael@0: case EGL_SURFACE_TYPE: match = (config->mSurfaceType & attribute[1]) == attribute[1]; break; michael@0: case EGL_TRANSPARENT_TYPE: match = config->mTransparentType == (EGLenum) attribute[1]; break; michael@0: case EGL_TRANSPARENT_BLUE_VALUE: match = config->mTransparentBlueValue == attribute[1]; break; michael@0: case EGL_TRANSPARENT_GREEN_VALUE: match = config->mTransparentGreenValue == attribute[1]; break; michael@0: case EGL_TRANSPARENT_RED_VALUE: match = config->mTransparentRedValue == attribute[1]; break; michael@0: case EGL_BIND_TO_TEXTURE_RGB: match = config->mBindToTextureRGB == (EGLBoolean) attribute[1]; break; michael@0: case EGL_BIND_TO_TEXTURE_RGBA: match = config->mBindToTextureRGBA == (EGLBoolean) attribute[1]; break; michael@0: case EGL_MIN_SWAP_INTERVAL: match = config->mMinSwapInterval == attribute[1]; break; michael@0: case EGL_MAX_SWAP_INTERVAL: match = config->mMaxSwapInterval == attribute[1]; break; michael@0: case EGL_LUMINANCE_SIZE: match = config->mLuminanceSize >= attribute[1]; break; michael@0: case EGL_ALPHA_MASK_SIZE: match = config->mAlphaMaskSize >= attribute[1]; break; michael@0: case EGL_COLOR_BUFFER_TYPE: match = config->mColorBufferType == (EGLenum) attribute[1]; break; michael@0: case EGL_RENDERABLE_TYPE: match = (config->mRenderableType & attribute[1]) == attribute[1]; break; michael@0: case EGL_MATCH_NATIVE_PIXMAP: match = false; UNIMPLEMENTED(); break; michael@0: case EGL_CONFORMANT: match = (config->mConformant & attribute[1]) == attribute[1]; break; michael@0: case EGL_MAX_PBUFFER_WIDTH: match = config->mMaxPBufferWidth >= attribute[1]; break; michael@0: case EGL_MAX_PBUFFER_HEIGHT: match = config->mMaxPBufferHeight >= attribute[1]; break; michael@0: case EGL_MAX_PBUFFER_PIXELS: match = config->mMaxPBufferPixels >= attribute[1]; break; michael@0: default: michael@0: return false; michael@0: } michael@0: michael@0: if (!match) michael@0: { michael@0: break; michael@0: } michael@0: michael@0: attribute += 2; michael@0: } michael@0: michael@0: if (match) michael@0: { michael@0: passed.push_back(&*config); michael@0: } michael@0: } michael@0: michael@0: if (configs) michael@0: { michael@0: sort(passed.begin(), passed.end(), SortConfig(attribList)); michael@0: michael@0: EGLint index; michael@0: for (index = 0; index < configSize && index < static_cast(passed.size()); index++) michael@0: { michael@0: configs[index] = passed[index]->getHandle(); michael@0: } michael@0: michael@0: *numConfig = index; michael@0: } michael@0: else michael@0: { michael@0: *numConfig = passed.size(); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: const egl::Config *ConfigSet::get(EGLConfig configHandle) michael@0: { michael@0: for (Iterator config = mSet.begin(); config != mSet.end(); config++) michael@0: { michael@0: if (config->getHandle() == configHandle) michael@0: { michael@0: return &(*config); michael@0: } michael@0: } michael@0: michael@0: return NULL; michael@0: } michael@0: }