diff options
Diffstat (limited to 'src/3rdparty/angle/src/libEGL')
-rw-r--r-- | src/3rdparty/angle/src/libEGL/Config.cpp | 399 | ||||
-rw-r--r-- | src/3rdparty/angle/src/libEGL/Config.h | 118 | ||||
-rw-r--r-- | src/3rdparty/angle/src/libEGL/Display.cpp | 1292 | ||||
-rw-r--r-- | src/3rdparty/angle/src/libEGL/Display.h | 167 | ||||
-rw-r--r-- | src/3rdparty/angle/src/libEGL/ShaderCache.h | 116 | ||||
-rw-r--r-- | src/3rdparty/angle/src/libEGL/Surface.cpp | 674 | ||||
-rw-r--r-- | src/3rdparty/angle/src/libEGL/Surface.h | 112 | ||||
-rw-r--r-- | src/3rdparty/angle/src/libEGL/libEGL.cpp | 1181 | ||||
-rw-r--r-- | src/3rdparty/angle/src/libEGL/libEGL.def | 36 | ||||
-rw-r--r-- | src/3rdparty/angle/src/libEGL/libEGL.rc | 102 | ||||
-rw-r--r-- | src/3rdparty/angle/src/libEGL/main.cpp | 165 | ||||
-rw-r--r-- | src/3rdparty/angle/src/libEGL/main.h | 61 | ||||
-rw-r--r-- | src/3rdparty/angle/src/libEGL/resource.h | 14 |
13 files changed, 4437 insertions, 0 deletions
diff --git a/src/3rdparty/angle/src/libEGL/Config.cpp b/src/3rdparty/angle/src/libEGL/Config.cpp new file mode 100644 index 0000000000..89bc8d89f4 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/Config.cpp @@ -0,0 +1,399 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// 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. + +#include "libEGL/Config.h" + +#include <algorithm> +#include <vector> + +#include "common/debug.h" + +using namespace std; + +namespace egl +{ +Config::Config(D3DDISPLAYMODE displayMode, EGLint minInterval, EGLint maxInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight) + : mDisplayMode(displayMode), mRenderTargetFormat(renderTargetFormat), mDepthStencilFormat(depthStencilFormat), mMultiSample(multiSample) +{ + set(displayMode, minInterval, maxInterval, renderTargetFormat, depthStencilFormat, multiSample, texWidth, texHeight); +} + +void Config::setDefaults() +{ + mBufferSize = 0; + mRedSize = 0; + mGreenSize = 0; + mBlueSize = 0; + mLuminanceSize = 0; + mAlphaSize = 0; + mAlphaMaskSize = 0; + mBindToTextureRGB = EGL_DONT_CARE; + mBindToTextureRGBA = EGL_DONT_CARE; + mColorBufferType = EGL_RGB_BUFFER; + mConfigCaveat = EGL_DONT_CARE; + mConfigID = EGL_DONT_CARE; + mConformant = 0; + mDepthSize = 0; + mLevel = 0; + mMatchNativePixmap = EGL_NONE; + mMaxPBufferWidth = 0; + mMaxPBufferHeight = 0; + mMaxPBufferPixels = 0; + mMaxSwapInterval = EGL_DONT_CARE; + mMinSwapInterval = EGL_DONT_CARE; + mNativeRenderable = EGL_DONT_CARE; + mNativeVisualID = 0; + mNativeVisualType = EGL_DONT_CARE; + mRenderableType = EGL_OPENGL_ES_BIT; + mSampleBuffers = 0; + mSamples = 0; + mStencilSize = 0; + mSurfaceType = EGL_WINDOW_BIT; + mTransparentType = EGL_NONE; + mTransparentRedValue = EGL_DONT_CARE; + mTransparentGreenValue = EGL_DONT_CARE; + mTransparentBlueValue = EGL_DONT_CARE; +} + +void Config::set(D3DDISPLAYMODE displayMode, EGLint minInterval, EGLint maxInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight) +{ + mBindToTextureRGB = EGL_FALSE; + mBindToTextureRGBA = EGL_FALSE; + switch (renderTargetFormat) + { + case D3DFMT_A1R5G5B5: + mBufferSize = 16; + mRedSize = 5; + mGreenSize = 5; + mBlueSize = 5; + mAlphaSize = 1; + break; + case D3DFMT_A2R10G10B10: + mBufferSize = 32; + mRedSize = 10; + mGreenSize = 10; + mBlueSize = 10; + mAlphaSize = 2; + break; + case D3DFMT_A8R8G8B8: + mBufferSize = 32; + mRedSize = 8; + mGreenSize = 8; + mBlueSize = 8; + mAlphaSize = 8; + mBindToTextureRGBA = true; + break; + case D3DFMT_R5G6B5: + mBufferSize = 16; + mRedSize = 5; + mGreenSize = 6; + mBlueSize = 5; + mAlphaSize = 0; + break; + case D3DFMT_X8R8G8B8: + mBufferSize = 32; + mRedSize = 8; + mGreenSize = 8; + mBlueSize = 8; + mAlphaSize = 0; + mBindToTextureRGB = true; + break; + default: + UNREACHABLE(); // Other formats should not be valid + } + + mLuminanceSize = 0; + mAlphaMaskSize = 0; + mColorBufferType = EGL_RGB_BUFFER; + mConfigCaveat = (displayMode.Format == renderTargetFormat) ? EGL_NONE : EGL_SLOW_CONFIG; + mConfigID = 0; + mConformant = EGL_OPENGL_ES2_BIT; + + switch (depthStencilFormat) + { + case D3DFMT_UNKNOWN: + mDepthSize = 0; + mStencilSize = 0; + break; +// case D3DFMT_D16_LOCKABLE: +// mDepthSize = 16; +// mStencilSize = 0; +// break; + case D3DFMT_D32: + mDepthSize = 32; + mStencilSize = 0; + break; + case D3DFMT_D15S1: + mDepthSize = 15; + mStencilSize = 1; + break; + case D3DFMT_D24S8: + mDepthSize = 24; + mStencilSize = 8; + break; + case D3DFMT_D24X8: + mDepthSize = 24; + mStencilSize = 0; + break; + case D3DFMT_D24X4S4: + mDepthSize = 24; + mStencilSize = 4; + break; + case D3DFMT_D16: + mDepthSize = 16; + mStencilSize = 0; + break; +// case D3DFMT_D32F_LOCKABLE: +// mDepthSize = 32; +// mStencilSize = 0; +// break; +// case D3DFMT_D24FS8: +// mDepthSize = 24; +// mStencilSize = 8; +// break; + default: + UNREACHABLE(); + } + + mLevel = 0; + mMatchNativePixmap = EGL_NONE; + mMaxPBufferWidth = texWidth; + mMaxPBufferHeight = texHeight; + mMaxPBufferPixels = texWidth*texHeight; + mMaxSwapInterval = maxInterval; + mMinSwapInterval = minInterval; + mNativeRenderable = EGL_FALSE; + mNativeVisualID = 0; + mNativeVisualType = 0; + mRenderableType = EGL_OPENGL_ES2_BIT; + mSampleBuffers = multiSample ? 1 : 0; + mSamples = multiSample; + mSurfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT; + mTransparentType = EGL_NONE; + mTransparentRedValue = 0; + mTransparentGreenValue = 0; + mTransparentBlueValue = 0; +} + +EGLConfig Config::getHandle() const +{ + return (EGLConfig)(size_t)mConfigID; +} + +SortConfig::SortConfig(const EGLint *attribList) + : mWantRed(false), mWantGreen(false), mWantBlue(false), mWantAlpha(false), mWantLuminance(false) +{ + scanForWantedComponents(attribList); +} + +void SortConfig::scanForWantedComponents(const EGLint *attribList) +{ + // [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(D3DDISPLAYMODE displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight) +{ + Config config(displayMode, minSwapInterval, maxSwapInterval, renderTargetFormat, depthStencilFormat, multiSample, texWidth, texHeight); + + mSet.insert(config); +} + +size_t ConfigSet::size() const +{ + return mSet.size(); +} + +bool ConfigSet::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig) +{ + vector<const Config*> passed; + passed.reserve(mSet.size()); + + for (Iterator config = mSet.begin(); config != mSet.end(); config++) + { + bool match = true; + const EGLint *attribute = attribList; + + while (attribute[0] != EGL_NONE) + { + switch (attribute[0]) + { + 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; + } + + if (!match) + { + break; + } + + attribute += 2; + } + + if (match) + { + passed.push_back(&*config); + } + } + + if (configs) + { + sort(passed.begin(), passed.end(), SortConfig(attribList)); + + 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; +} + +const egl::Config *ConfigSet::get(EGLConfig configHandle) +{ + for (Iterator config = mSet.begin(); config != mSet.end(); config++) + { + if (config->getHandle() == configHandle) + { + return &(*config); + } + } + + return NULL; +} +} diff --git a/src/3rdparty/angle/src/libEGL/Config.h b/src/3rdparty/angle/src/libEGL/Config.h new file mode 100644 index 0000000000..95626ed1ad --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/Config.h @@ -0,0 +1,118 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Config.h: Defines 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. + +#ifndef INCLUDE_CONFIG_H_ +#define INCLUDE_CONFIG_H_ + +#define EGLAPI +#include <EGL/egl.h> +#include <d3d9.h> + +#include <set> + +#include "common/angleutils.h" + +namespace egl +{ +class Display; + +class Config +{ + public: + Config(D3DDISPLAYMODE displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight); + + void setDefaults(); + void set(D3DDISPLAYMODE displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight); + EGLConfig getHandle() const; + + const D3DDISPLAYMODE mDisplayMode; + const D3DFORMAT mRenderTargetFormat; + const D3DFORMAT mDepthStencilFormat; + const EGLint mMultiSample; + + EGLint mBufferSize; // Depth of the color buffer + EGLint mRedSize; // Bits of Red in the color buffer + EGLint mGreenSize; // Bits of Green in the color buffer + EGLint mBlueSize; // Bits of Blue in the color buffer + EGLint mLuminanceSize; // Bits of Luminance in the color buffer + EGLint mAlphaSize; // Bits of Alpha in the color buffer + EGLint mAlphaMaskSize; // Bits of Alpha Mask in the mask buffer + EGLBoolean mBindToTextureRGB; // True if bindable to RGB textures. + EGLBoolean mBindToTextureRGBA; // True if bindable to RGBA textures. + EGLenum mColorBufferType; // Color buffer type + EGLenum mConfigCaveat; // Any caveats for the configuration + EGLint mConfigID; // Unique EGLConfig identifier + EGLint mConformant; // Whether contexts created with this config are conformant + EGLint mDepthSize; // Bits of Z in the depth buffer + EGLint mLevel; // Frame buffer level + EGLBoolean mMatchNativePixmap; // Match the native pixmap format + EGLint mMaxPBufferWidth; // Maximum width of pbuffer + EGLint mMaxPBufferHeight; // Maximum height of pbuffer + EGLint mMaxPBufferPixels; // Maximum size of pbuffer + EGLint mMaxSwapInterval; // Maximum swap interval + EGLint mMinSwapInterval; // Minimum swap interval + EGLBoolean mNativeRenderable; // EGL_TRUE if native rendering APIs can render to surface + EGLint mNativeVisualID; // Handle of corresponding native visual + EGLint mNativeVisualType; // Native visual type of the associated visual + EGLint mRenderableType; // Which client rendering APIs are supported. + EGLint mSampleBuffers; // Number of multisample buffers + EGLint mSamples; // Number of samples per pixel + EGLint mStencilSize; // Bits of Stencil in the stencil buffer + EGLint mSurfaceType; // Which types of EGL surfaces are supported. + EGLenum mTransparentType; // Type of transparency supported + EGLint mTransparentRedValue; // Transparent red value + EGLint mTransparentGreenValue; // Transparent green value + EGLint mTransparentBlueValue; // Transparent blue value +}; + +// Function object used by STL sorting routines for ordering Configs according to [EGL] section 3.4.1 page 24. +class SortConfig +{ + public: + explicit SortConfig(const EGLint *attribList); + + bool operator()(const Config *x, const Config *y) const; + bool operator()(const Config &x, const Config &y) const; + + private: + void scanForWantedComponents(const EGLint *attribList); + EGLint wantedComponentsSize(const Config &config) const; + + bool mWantRed; + bool mWantGreen; + bool mWantBlue; + bool mWantAlpha; + bool mWantLuminance; +}; + +class ConfigSet +{ + friend Display; + + public: + ConfigSet(); + + void add(D3DDISPLAYMODE displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight); + size_t size() const; + bool getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig); + const egl::Config *get(EGLConfig configHandle); + + private: + DISALLOW_COPY_AND_ASSIGN(ConfigSet); + + typedef std::set<Config, SortConfig> Set; + typedef Set::iterator Iterator; + Set mSet; + + static const EGLint mSortAttribs[]; +}; +} + +#endif // INCLUDE_CONFIG_H_ diff --git a/src/3rdparty/angle/src/libEGL/Display.cpp b/src/3rdparty/angle/src/libEGL/Display.cpp new file mode 100644 index 0000000000..a2dee6d964 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/Display.cpp @@ -0,0 +1,1292 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Display.cpp: Implements the egl::Display class, representing the abstract +// display on which graphics are drawn. Implements EGLDisplay. +// [EGL 1.4] section 2.1.2 page 3. + +#include "libEGL/Display.h" + +#include <algorithm> +#include <map> +#include <vector> + +#include "common/debug.h" +#include "libGLESv2/mathutil.h" +#include "libGLESv2/utilities.h" + +#include "libEGL/main.h" + +// Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros +#define REF_RAST 0 + +// The "Debug This Pixel..." feature in PIX often fails when using the +// D3D9Ex interfaces. In order to get debug pixel to work on a Vista/Win 7 +// machine, define "ANGLE_ENABLE_D3D9EX=0" in your project file. +#if !defined(ANGLE_ENABLE_D3D9EX) +// Enables use of the IDirect3D9Ex interface, when available +#define ANGLE_ENABLE_D3D9EX 1 +#endif // !defined(ANGLE_ENABLE_D3D9EX) + +namespace egl +{ +namespace +{ + typedef std::map<EGLNativeDisplayType, Display*> DisplayMap; + DisplayMap displays; +} + +egl::Display *Display::getDisplay(EGLNativeDisplayType displayId) +{ + if (displays.find(displayId) != displays.end()) + { + return displays[displayId]; + } + + egl::Display *display = NULL; + + if (displayId == EGL_DEFAULT_DISPLAY) + { + display = new egl::Display(displayId, (HDC)NULL, false); + } + else if (displayId == EGL_SOFTWARE_DISPLAY_ANGLE) + { + display = new egl::Display(displayId, (HDC)NULL, true); + } + else + { + // FIXME: Check if displayId is a valid display device context + + display = new egl::Display(displayId, (HDC)displayId, false); + } + + displays[displayId] = display; + return display; +} + +Display::Display(EGLNativeDisplayType displayId, HDC deviceContext, bool software) : mDc(deviceContext) +{ + mD3d9Module = NULL; + + mD3d9 = NULL; + mD3d9Ex = NULL; + mDevice = NULL; + mDeviceEx = NULL; + mDeviceWindow = NULL; + + mAdapter = D3DADAPTER_DEFAULT; + + #if REF_RAST == 1 || defined(FORCE_REF_RAST) + mDeviceType = D3DDEVTYPE_REF; + #else + mDeviceType = D3DDEVTYPE_HAL; + #endif + + mMinSwapInterval = 1; + mMaxSwapInterval = 1; + mSoftwareDevice = software; + mDisplayId = displayId; + mDeviceLost = false; +} + +Display::~Display() +{ + terminate(); + + DisplayMap::iterator thisDisplay = displays.find(mDisplayId); + + if (thisDisplay != displays.end()) + { + displays.erase(thisDisplay); + } +} + +bool Display::initialize() +{ + if (isInitialized()) + { + return true; + } + + if (mSoftwareDevice) + { + mD3d9Module = GetModuleHandle(TEXT("swiftshader_d3d9.dll")); + } + else + { + mD3d9Module = GetModuleHandle(TEXT("d3d9.dll")); + } + if (mD3d9Module == NULL) + { + terminate(); + return false; + } + + typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**); + Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast<Direct3DCreate9ExFunc>(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex")); + + // Use Direct3D9Ex if available. Among other things, this version is less + // inclined to report a lost context, for example when the user switches + // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available. + if (ANGLE_ENABLE_D3D9EX && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex))) + { + ASSERT(mD3d9Ex); + mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast<void**>(&mD3d9)); + ASSERT(mD3d9); + } + else + { + mD3d9 = Direct3DCreate9(D3D_SDK_VERSION); + } + + if (mD3d9) + { + if (mDc != NULL) + { + // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to + } + + HRESULT result; + + // Give up on getting device caps after about one second. + for (int i = 0; i < 10; ++i) + { + result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps); + + if (SUCCEEDED(result)) + { + break; + } + else if (result == D3DERR_NOTAVAILABLE) + { + Sleep(100); // Give the driver some time to initialize/recover + } + else if (FAILED(result)) // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, D3DERR_INVALIDDEVICE, or another error we can't recover from + { + terminate(); + return error(EGL_BAD_ALLOC, false); + } + } + + if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(2, 0)) + { + terminate(); + return error(EGL_NOT_INITIALIZED, false); + } + + // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture to a render target texture is not supported. + // This is required by Texture2D::convertToRenderTarget. + if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0) + { + terminate(); + return error(EGL_NOT_INITIALIZED, false); + } + + mMinSwapInterval = 4; + mMaxSwapInterval = 0; + + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) {mMinSwapInterval = std::min(mMinSwapInterval, 0); mMaxSwapInterval = std::max(mMaxSwapInterval, 0);} + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE) {mMinSwapInterval = std::min(mMinSwapInterval, 1); mMaxSwapInterval = std::max(mMaxSwapInterval, 1);} + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO) {mMinSwapInterval = std::min(mMinSwapInterval, 2); mMaxSwapInterval = std::max(mMaxSwapInterval, 2);} + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE) {mMinSwapInterval = std::min(mMinSwapInterval, 3); mMaxSwapInterval = std::max(mMaxSwapInterval, 3);} + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR) {mMinSwapInterval = std::min(mMinSwapInterval, 4); mMaxSwapInterval = std::max(mMaxSwapInterval, 4);} + + mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier); + + // ATI cards on XP have problems with non-power-of-two textures. + mSupportsNonPower2Textures = !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) && + !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && + !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) && + !(getComparableOSVersion() < versionWindowsVista && mAdapterIdentifier.VendorId == VENDOR_ID_AMD); + + const D3DFORMAT renderTargetFormats[] = + { + D3DFMT_A1R5G5B5, + // D3DFMT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value. + D3DFMT_A8R8G8B8, + D3DFMT_R5G6B5, + // D3DFMT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format + D3DFMT_X8R8G8B8 + }; + + const D3DFORMAT depthStencilFormats[] = + { + D3DFMT_UNKNOWN, + // D3DFMT_D16_LOCKABLE, + D3DFMT_D32, + // D3DFMT_D15S1, + D3DFMT_D24S8, + D3DFMT_D24X8, + // D3DFMT_D24X4S4, + D3DFMT_D16, + // D3DFMT_D32F_LOCKABLE, + // D3DFMT_D24FS8 + }; + + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + ConfigSet configSet; + + for (int formatIndex = 0; formatIndex < sizeof(renderTargetFormats) / sizeof(D3DFORMAT); formatIndex++) + { + D3DFORMAT renderTargetFormat = renderTargetFormats[formatIndex]; + + HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, renderTargetFormat); + + if (SUCCEEDED(result)) + { + for (int depthStencilIndex = 0; depthStencilIndex < sizeof(depthStencilFormats) / sizeof(D3DFORMAT); depthStencilIndex++) + { + D3DFORMAT depthStencilFormat = depthStencilFormats[depthStencilIndex]; + HRESULT result = D3D_OK; + + if(depthStencilFormat != D3DFMT_UNKNOWN) + { + result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, depthStencilFormat); + } + + if (SUCCEEDED(result)) + { + if(depthStencilFormat != D3DFMT_UNKNOWN) + { + result = mD3d9->CheckDepthStencilMatch(mAdapter, mDeviceType, currentDisplayMode.Format, renderTargetFormat, depthStencilFormat); + } + + if (SUCCEEDED(result)) + { + // FIXME: enumerate multi-sampling + + configSet.add(currentDisplayMode, mMinSwapInterval, mMaxSwapInterval, renderTargetFormat, depthStencilFormat, 0, + mDeviceCaps.MaxTextureWidth, mDeviceCaps.MaxTextureHeight); + } + } + } + } + } + + // Give the sorted configs a unique ID and store them internally + EGLint index = 1; + for (ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++) + { + Config configuration = *config; + configuration.mConfigID = index; + index++; + + mConfigSet.mSet.insert(configuration); + } + } + + if (!isInitialized()) + { + terminate(); + + return false; + } + + initExtensionString(); + + static const TCHAR windowName[] = TEXT("AngleHiddenWindow"); + static const TCHAR className[] = TEXT("STATIC"); + + mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL); + + if (!createDevice()) + { + terminate(); + return false; + } + + mVertexShaderCache.initialize(mDevice); + mPixelShaderCache.initialize(mDevice); + + return true; +} + +void Display::terminate() +{ + while (!mSurfaceSet.empty()) + { + destroySurface(*mSurfaceSet.begin()); + } + + while (!mContextSet.empty()) + { + destroyContext(*mContextSet.begin()); + } + + while (!mEventQueryPool.empty()) + { + mEventQueryPool.back()->Release(); + mEventQueryPool.pop_back(); + } + + mVertexShaderCache.clear(); + mPixelShaderCache.clear(); + + if (mDevice) + { + // If the device is lost, reset it first to prevent leaving the driver in an unstable state + if (testDeviceLost()) + { + resetDevice(); + } + + mDevice->Release(); + mDevice = NULL; + } + + if (mDeviceEx) + { + mDeviceEx->Release(); + mDeviceEx = NULL; + } + + if (mD3d9) + { + mD3d9->Release(); + mD3d9 = NULL; + } + + if (mDeviceWindow) + { + DestroyWindow(mDeviceWindow); + mDeviceWindow = NULL; + } + + if (mD3d9Ex) + { + mD3d9Ex->Release(); + mD3d9Ex = NULL; + } + + if (mD3d9Module) + { + mD3d9Module = NULL; + } +} + +void Display::startScene() +{ + if (!mSceneStarted) + { + long result = mDevice->BeginScene(); + if (SUCCEEDED(result)) { + // This is defensive checking against the device being + // lost at unexpected times. + mSceneStarted = true; + } + } +} + +void Display::endScene() +{ + if (mSceneStarted) + { + // EndScene can fail if the device was lost, for example due + // to a TDR during a draw call. + mDevice->EndScene(); + mSceneStarted = false; + } +} + +bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig) +{ + return mConfigSet.getConfigs(configs, attribList, configSize, numConfig); +} + +bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value) +{ + const egl::Config *configuration = mConfigSet.get(config); + + switch (attribute) + { + case EGL_BUFFER_SIZE: *value = configuration->mBufferSize; break; + case EGL_ALPHA_SIZE: *value = configuration->mAlphaSize; break; + case EGL_BLUE_SIZE: *value = configuration->mBlueSize; break; + case EGL_GREEN_SIZE: *value = configuration->mGreenSize; break; + case EGL_RED_SIZE: *value = configuration->mRedSize; break; + case EGL_DEPTH_SIZE: *value = configuration->mDepthSize; break; + case EGL_STENCIL_SIZE: *value = configuration->mStencilSize; break; + case EGL_CONFIG_CAVEAT: *value = configuration->mConfigCaveat; break; + case EGL_CONFIG_ID: *value = configuration->mConfigID; break; + case EGL_LEVEL: *value = configuration->mLevel; break; + case EGL_NATIVE_RENDERABLE: *value = configuration->mNativeRenderable; break; + case EGL_NATIVE_VISUAL_TYPE: *value = configuration->mNativeVisualType; break; + case EGL_SAMPLES: *value = configuration->mSamples; break; + case EGL_SAMPLE_BUFFERS: *value = configuration->mSampleBuffers; break; + case EGL_SURFACE_TYPE: *value = configuration->mSurfaceType; break; + case EGL_TRANSPARENT_TYPE: *value = configuration->mTransparentType; break; + case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->mTransparentBlueValue; break; + case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->mTransparentGreenValue; break; + case EGL_TRANSPARENT_RED_VALUE: *value = configuration->mTransparentRedValue; break; + case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->mBindToTextureRGB; break; + case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->mBindToTextureRGBA; break; + case EGL_MIN_SWAP_INTERVAL: *value = configuration->mMinSwapInterval; break; + case EGL_MAX_SWAP_INTERVAL: *value = configuration->mMaxSwapInterval; break; + case EGL_LUMINANCE_SIZE: *value = configuration->mLuminanceSize; break; + case EGL_ALPHA_MASK_SIZE: *value = configuration->mAlphaMaskSize; break; + case EGL_COLOR_BUFFER_TYPE: *value = configuration->mColorBufferType; break; + case EGL_RENDERABLE_TYPE: *value = configuration->mRenderableType; break; + case EGL_MATCH_NATIVE_PIXMAP: *value = false; UNIMPLEMENTED(); break; + case EGL_CONFORMANT: *value = configuration->mConformant; break; + case EGL_MAX_PBUFFER_WIDTH: *value = configuration->mMaxPBufferWidth; break; + case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->mMaxPBufferHeight; break; + case EGL_MAX_PBUFFER_PIXELS: *value = configuration->mMaxPBufferPixels; break; + default: + return false; + } + + return true; +} + +bool Display::createDevice() +{ + D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); + DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES; + + HRESULT result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST) + { + return error(EGL_BAD_ALLOC, false); + } + + if (FAILED(result)) + { + result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST); + return error(EGL_BAD_ALLOC, false); + } + } + + if (mD3d9Ex) + { + result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**) &mDeviceEx); + ASSERT(SUCCEEDED(result)); + } + + initializeDevice(); + + return true; +} + +// do any one-time device initialization +// NOTE: this is also needed after a device lost/reset +// to reset the scene status and ensure the default states are reset. +void Display::initializeDevice() +{ + // Permanent non-default states + mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE); + mDevice->SetRenderState(D3DRS_LASTPIXEL, FALSE); + + if (mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) + { + mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, (DWORD&)mDeviceCaps.MaxPointSize); + } + else + { + mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, 0x3F800000); // 1.0f + } + + mSceneStarted = false; +} + +bool Display::resetDevice() +{ + D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); + + HRESULT result = D3D_OK; + bool lost = testDeviceLost(); + int attempts = 3; + + while (lost && attempts > 0) + { + if (mDeviceEx) + { + Sleep(500); // Give the graphics driver some CPU time + result = mDeviceEx->ResetEx(&presentParameters, NULL); + } + else + { + result = mDevice->TestCooperativeLevel(); + + while (result == D3DERR_DEVICELOST) + { + Sleep(100); // Give the graphics driver some CPU time + result = mDevice->TestCooperativeLevel(); + } + + if (result == D3DERR_DEVICENOTRESET) + { + result = mDevice->Reset(&presentParameters); + } + } + + lost = testDeviceLost(); + attempts --; + } + + if (FAILED(result)) + { + ERR("Reset/ResetEx failed multiple times: 0x%08X", result); + return error(EGL_BAD_ALLOC, false); + } + + // reset device defaults + initializeDevice(); + + return true; +} + +EGLSurface Display::createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList) +{ + const Config *configuration = mConfigSet.get(config); + EGLint postSubBufferSupported = EGL_FALSE; + + if (attribList) + { + while (*attribList != EGL_NONE) + { + switch (attribList[0]) + { + case EGL_RENDER_BUFFER: + switch (attribList[1]) + { + case EGL_BACK_BUFFER: + break; + case EGL_SINGLE_BUFFER: + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported + default: + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + break; + case EGL_POST_SUB_BUFFER_SUPPORTED_NV: + postSubBufferSupported = attribList[1]; + break; + case EGL_VG_COLORSPACE: + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + case EGL_VG_ALPHA_FORMAT: + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + default: + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + + attribList += 2; + } + } + + if (hasExistingWindowSurface(window)) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } + + if (testDeviceLost()) + { + if (!restoreLostDevice()) + return EGL_NO_SURFACE; + } + + Surface *surface = new Surface(this, configuration, window, postSubBufferSupported); + + if (!surface->initialize()) + { + delete surface; + return EGL_NO_SURFACE; + } + + mSurfaceSet.insert(surface); + + return success(surface); +} + +EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList) +{ + EGLint width = 0, height = 0; + EGLenum textureFormat = EGL_NO_TEXTURE; + EGLenum textureTarget = EGL_NO_TEXTURE; + const Config *configuration = mConfigSet.get(config); + + if (attribList) + { + while (*attribList != EGL_NONE) + { + switch (attribList[0]) + { + case EGL_WIDTH: + width = attribList[1]; + break; + case EGL_HEIGHT: + height = attribList[1]; + break; + case EGL_LARGEST_PBUFFER: + if (attribList[1] != EGL_FALSE) + UNIMPLEMENTED(); // FIXME + break; + case EGL_TEXTURE_FORMAT: + switch (attribList[1]) + { + case EGL_NO_TEXTURE: + case EGL_TEXTURE_RGB: + case EGL_TEXTURE_RGBA: + textureFormat = attribList[1]; + break; + default: + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + break; + case EGL_TEXTURE_TARGET: + switch (attribList[1]) + { + case EGL_NO_TEXTURE: + case EGL_TEXTURE_2D: + textureTarget = attribList[1]; + break; + default: + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + break; + case EGL_MIPMAP_TEXTURE: + if (attribList[1] != EGL_FALSE) + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + break; + case EGL_VG_COLORSPACE: + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + case EGL_VG_ALPHA_FORMAT: + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + default: + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + + attribList += 2; + } + } + + if (width < 0 || height < 0) + { + return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); + } + + if (width == 0 || height == 0) + { + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + + if (textureFormat != EGL_NO_TEXTURE && !getNonPower2TextureSupport() && (!gl::isPow2(width) || !gl::isPow2(height))) + { + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + } + + if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) || + (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE)) + { + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + } + + if (!(configuration->mSurfaceType & EGL_PBUFFER_BIT)) + { + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + } + + if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) || + (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE)) + { + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + + if (testDeviceLost()) + { + if (!restoreLostDevice()) + return EGL_NO_SURFACE; + } + + Surface *surface = new Surface(this, configuration, shareHandle, width, height, textureFormat, textureTarget); + + if (!surface->initialize()) + { + delete surface; + return EGL_NO_SURFACE; + } + + mSurfaceSet.insert(surface); + + return success(surface); +} + +EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext, bool notifyResets, bool robustAccess) +{ + if (!mDevice) + { + if (!createDevice()) + { + return NULL; + } + } + else if (testDeviceLost()) // Lost device + { + if (!restoreLostDevice()) + return NULL; + } + + const egl::Config *config = mConfigSet.get(configHandle); + + gl::Context *context = glCreateContext(config, shareContext, notifyResets, robustAccess); + mContextSet.insert(context); + mDeviceLost = false; + + return context; +} + +bool Display::restoreLostDevice() +{ + for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++) + { + if ((*ctx)->isResetNotificationEnabled()) + return false; // If reset notifications have been requested, application must delete all contexts first + } + + // Release surface resources to make the Reset() succeed + for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) + { + (*surface)->release(); + } + + while (!mEventQueryPool.empty()) + { + mEventQueryPool.back()->Release(); + mEventQueryPool.pop_back(); + } + + mVertexShaderCache.clear(); + mPixelShaderCache.clear(); + + if (!resetDevice()) + { + return false; + } + + // Restore any surfaces that may have been lost + for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) + { + (*surface)->resetSwapChain(); + } + + return true; +} + + +void Display::destroySurface(egl::Surface *surface) +{ + delete surface; + mSurfaceSet.erase(surface); +} + +void Display::destroyContext(gl::Context *context) +{ + glDestroyContext(context); + mContextSet.erase(context); +} + +void Display::notifyDeviceLost() +{ + for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++) + { + (*context)->markContextLost(); + } + mDeviceLost = true; + error(EGL_CONTEXT_LOST); +} + +bool Display::isDeviceLost() +{ + return mDeviceLost; +} + +bool Display::isInitialized() const +{ + return mD3d9 != NULL && mConfigSet.size() > 0; +} + +bool Display::isValidConfig(EGLConfig config) +{ + return mConfigSet.get(config) != NULL; +} + +bool Display::isValidContext(gl::Context *context) +{ + return mContextSet.find(context) != mContextSet.end(); +} + +bool Display::isValidSurface(egl::Surface *surface) +{ + return mSurfaceSet.find(surface) != mSurfaceSet.end(); +} + +bool Display::hasExistingWindowSurface(HWND window) +{ + for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) + { + if ((*surface)->getWindowHandle() == window) + { + return true; + } + } + + return false; +} + +EGLint Display::getMinSwapInterval() +{ + return mMinSwapInterval; +} + +EGLint Display::getMaxSwapInterval() +{ + return mMaxSwapInterval; +} + +IDirect3DDevice9 *Display::getDevice() +{ + if (!mDevice) + { + if (!createDevice()) + { + return NULL; + } + } + + return mDevice; +} + +D3DCAPS9 Display::getDeviceCaps() +{ + return mDeviceCaps; +} + +D3DADAPTER_IDENTIFIER9 *Display::getAdapterIdentifier() +{ + return &mAdapterIdentifier; +} + +bool Display::testDeviceLost() +{ + if (mDeviceEx) + { + return FAILED(mDeviceEx->CheckDeviceState(NULL)); + } + else if (mDevice) + { + return FAILED(mDevice->TestCooperativeLevel()); + } + + return false; // No device yet, so no reset required +} + +bool Display::testDeviceResettable() +{ + HRESULT status = D3D_OK; + + if (mDeviceEx) + { + status = mDeviceEx->CheckDeviceState(NULL); + } + else if (mDevice) + { + status = mDevice->TestCooperativeLevel(); + } + + switch (status) + { + case D3DERR_DEVICENOTRESET: + case D3DERR_DEVICEHUNG: + return true; + default: + return false; + } +} + +void Display::sync(bool block) +{ + HRESULT result; + + IDirect3DQuery9* query = allocateEventQuery(); + if (!query) + { + return; + } + + result = query->Issue(D3DISSUE_END); + ASSERT(SUCCEEDED(result)); + + do + { + result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); + + if(block && result == S_FALSE) + { + // Keep polling, but allow other threads to do something useful first + Sleep(0); + // explicitly check for device loss + // some drivers seem to return S_FALSE even if the device is lost + // instead of D3DERR_DEVICELOST like they should + if (testDeviceLost()) + { + result = D3DERR_DEVICELOST; + } + } + } + while(block && result == S_FALSE); + + freeEventQuery(query); + + if (isDeviceLostError(result)) + { + notifyDeviceLost(); + } +} + +IDirect3DQuery9* Display::allocateEventQuery() +{ + IDirect3DQuery9 *query = NULL; + + if (mEventQueryPool.empty()) + { + HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query); + ASSERT(SUCCEEDED(result)); + } + else + { + query = mEventQueryPool.back(); + mEventQueryPool.pop_back(); + } + + return query; +} + +void Display::freeEventQuery(IDirect3DQuery9* query) +{ + if (mEventQueryPool.size() > 1000) + { + query->Release(); + } + else + { + mEventQueryPool.push_back(query); + } +} + +void Display::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray) +{ + for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++) + { + HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format, + TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL); + + multiSampleArray[multiSampleIndex] = SUCCEEDED(result); + } +} + +bool Display::getDXT1TextureSupport() +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1)); +} + +bool Display::getDXT3TextureSupport() +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT3)); +} + +bool Display::getDXT5TextureSupport() +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT5)); +} + +// we use INTZ for depth textures in Direct3D9 +// we also want NULL texture support to ensure the we can make depth-only FBOs +// see http://aras-p.info/texts/D3D9GPUHacks.html +bool Display::getDepthTextureSupport() const +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + bool intz = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, + D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, D3DFMT_INTZ)); + bool null = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, + D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, D3DFMT_NULL)); + + return intz && null; +} + +bool Display::getFloat32TextureSupport(bool *filtering, bool *renderable) +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, + D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) && + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, + D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F)); + + *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, + D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F))&& + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, + D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F)); + + if (!*filtering && !*renderable) + { + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, + D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) && + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, + D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F)); + } + else + { + return true; + } +} + +bool Display::getFloat16TextureSupport(bool *filtering, bool *renderable) +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, + D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) && + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, + D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F)); + + *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, + D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) && + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, + D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F)); + + if (!*filtering && !*renderable) + { + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, + D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) && + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, + D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F)); + } + else + { + return true; + } +} + +bool Display::getLuminanceTextureSupport() +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8)); +} + +bool Display::getLuminanceAlphaTextureSupport() +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8)); +} + +float Display::getTextureFilterAnisotropySupport() const +{ + // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per the spec + if ((mDeviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) && (mDeviceCaps.MaxAnisotropy >= 2)) + { + return mDeviceCaps.MaxAnisotropy; + } + return 1.0f; +} + +D3DPOOL Display::getBufferPool(DWORD usage) const +{ + if (mD3d9Ex != NULL) + { + return D3DPOOL_DEFAULT; + } + else + { + if (!(usage & D3DUSAGE_DYNAMIC)) + { + return D3DPOOL_MANAGED; + } + } + + return D3DPOOL_DEFAULT; +} + +D3DPOOL Display::getTexturePool(DWORD usage) const +{ + if (mD3d9Ex != NULL) + { + return D3DPOOL_DEFAULT; + } + else + { + if (!(usage & (D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_RENDERTARGET))) + { + return D3DPOOL_MANAGED; + } + } + + return D3DPOOL_DEFAULT; +} + +bool Display::getEventQuerySupport() +{ + IDirect3DQuery9 *query = allocateEventQuery(); + if (query) + { + freeEventQuery(query); + return true; + } + else + { + return false; + } +} + +D3DPRESENT_PARAMETERS Display::getDefaultPresentParameters() +{ + D3DPRESENT_PARAMETERS presentParameters = {0}; + + // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters. + presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + presentParameters.BackBufferCount = 1; + presentParameters.BackBufferFormat = D3DFMT_UNKNOWN; + presentParameters.BackBufferWidth = 1; + presentParameters.BackBufferHeight = 1; + presentParameters.EnableAutoDepthStencil = FALSE; + presentParameters.Flags = 0; + presentParameters.hDeviceWindow = mDeviceWindow; + presentParameters.MultiSampleQuality = 0; + presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; + presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; + presentParameters.Windowed = TRUE; + + return presentParameters; +} + +void Display::initExtensionString() +{ + HMODULE swiftShader = GetModuleHandle(TEXT("swiftshader_d3d9.dll")); + + mExtensionString = ""; + + // Multi-vendor (EXT) extensions + mExtensionString += "EGL_EXT_create_context_robustness "; + + // ANGLE-specific extensions + if (shareHandleSupported()) + { + mExtensionString += "EGL_ANGLE_d3d_share_handle_client_buffer "; + } + + mExtensionString += "EGL_ANGLE_query_surface_pointer "; + + if (swiftShader) + { + mExtensionString += "EGL_ANGLE_software_display "; + } + + if (shareHandleSupported()) + { + mExtensionString += "EGL_ANGLE_surface_d3d_texture_2d_share_handle "; + } + + mExtensionString += "EGL_NV_post_sub_buffer"; + + std::string::size_type end = mExtensionString.find_last_not_of(' '); + if (end != std::string::npos) + { + mExtensionString.resize(end+1); + } +} + +const char *Display::getExtensionString() const +{ + return mExtensionString.c_str(); +} + +bool Display::shareHandleSupported() const +{ + // PIX doesn't seem to support using share handles, so disable them. + return isD3d9ExDevice() && !gl::perfActive(); +} + +IDirect3DVertexShader9 *Display::createVertexShader(const DWORD *function, size_t length) +{ + return mVertexShaderCache.create(function, length); +} + +IDirect3DPixelShader9 *Display::createPixelShader(const DWORD *function, size_t length) +{ + return mPixelShaderCache.create(function, length); +} + +// Only Direct3D 10 ready devices support all the necessary vertex texture formats. +// We test this using D3D9 by checking support for the R16F format. +bool Display::getVertexTextureSupport() const +{ + if (!isInitialized() || mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(3, 0)) + { + return false; + } + + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F); + + return SUCCEEDED(result); +} + +bool Display::getNonPower2TextureSupport() const +{ + return mSupportsNonPower2Textures; +} + +bool Display::getOcclusionQuerySupport() const +{ + if (!isInitialized()) + { + return false; + } + + IDirect3DQuery9 *query = NULL; + HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &query); + + if (SUCCEEDED(result) && query) + { + query->Release(); + return true; + } + else + { + return false; + } +} + +bool Display::getInstancingSupport() const +{ + return mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0); +} + +} diff --git a/src/3rdparty/angle/src/libEGL/Display.h b/src/3rdparty/angle/src/libEGL/Display.h new file mode 100644 index 0000000000..23b57b74c6 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/Display.h @@ -0,0 +1,167 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Display.h: Defines the egl::Display class, representing the abstract +// display on which graphics are drawn. Implements EGLDisplay. +// [EGL 1.4] section 2.1.2 page 3. + +#ifndef LIBEGL_DISPLAY_H_ +#define LIBEGL_DISPLAY_H_ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#include <d3d9.h> + +#include <set> +#include <vector> + +#include "libGLESv2/Context.h" + +#include "libEGL/Config.h" +#include "libEGL/ShaderCache.h" +#include "libEGL/Surface.h" + +const int versionWindowsVista = MAKEWORD(0x00, 0x06); +const int versionWindows7 = MAKEWORD(0x01, 0x06); + +// Return the version of the operating system in a format suitable for ordering +// comparison. +inline int getComparableOSVersion() +{ + DWORD version = GetVersion(); + int majorVersion = LOBYTE(LOWORD(version)); + int minorVersion = HIBYTE(LOWORD(version)); + return MAKEWORD(minorVersion, majorVersion); +} + +namespace egl +{ +class Display +{ + public: + ~Display(); + + bool initialize(); + void terminate(); + + virtual void startScene(); + virtual void endScene(); + + static egl::Display *getDisplay(EGLNativeDisplayType displayId); + + bool getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig); + bool getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value); + + EGLSurface createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList); + EGLSurface createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList); + EGLContext createContext(EGLConfig configHandle, const gl::Context *shareContext, bool notifyResets, bool robustAccess); + + void destroySurface(egl::Surface *surface); + void destroyContext(gl::Context *context); + + bool isInitialized() const; + bool isValidConfig(EGLConfig config); + bool isValidContext(gl::Context *context); + bool isValidSurface(egl::Surface *surface); + bool hasExistingWindowSurface(HWND window); + + EGLint getMinSwapInterval(); + EGLint getMaxSwapInterval(); + + virtual IDirect3DDevice9 *getDevice(); + virtual D3DCAPS9 getDeviceCaps(); + virtual D3DADAPTER_IDENTIFIER9 *getAdapterIdentifier(); + virtual bool testDeviceLost(); + virtual bool testDeviceResettable(); + virtual void sync(bool block); + virtual IDirect3DQuery9* allocateEventQuery(); + virtual void freeEventQuery(IDirect3DQuery9* query); + virtual void getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray); + virtual bool getDXT1TextureSupport(); + virtual bool getDXT3TextureSupport(); + virtual bool getDXT5TextureSupport(); + virtual bool getEventQuerySupport(); + virtual bool getFloat32TextureSupport(bool *filtering, bool *renderable); + virtual bool getFloat16TextureSupport(bool *filtering, bool *renderable); + virtual bool getLuminanceTextureSupport(); + virtual bool getLuminanceAlphaTextureSupport(); + virtual bool getVertexTextureSupport() const; + virtual bool getNonPower2TextureSupport() const; + virtual bool getDepthTextureSupport() const; + virtual bool getOcclusionQuerySupport() const; + virtual bool getInstancingSupport() const; + virtual float getTextureFilterAnisotropySupport() const; + virtual D3DPOOL getBufferPool(DWORD usage) const; + virtual D3DPOOL getTexturePool(DWORD usage) const; + + virtual void notifyDeviceLost(); + bool isDeviceLost(); + + bool isD3d9ExDevice() const { return mD3d9Ex != NULL; } + const char *getExtensionString() const; + bool shareHandleSupported() const; + + virtual IDirect3DVertexShader9 *createVertexShader(const DWORD *function, size_t length); + virtual IDirect3DPixelShader9 *createPixelShader(const DWORD *function, size_t length); + + private: + DISALLOW_COPY_AND_ASSIGN(Display); + + Display(EGLNativeDisplayType displayId, HDC deviceContext, bool software); + + D3DPRESENT_PARAMETERS getDefaultPresentParameters(); + + bool restoreLostDevice(); + + EGLNativeDisplayType mDisplayId; + const HDC mDc; + + HMODULE mD3d9Module; + + UINT mAdapter; + D3DDEVTYPE mDeviceType; + IDirect3D9 *mD3d9; // Always valid after successful initialization. + IDirect3D9Ex *mD3d9Ex; // Might be null if D3D9Ex is not supported. + IDirect3DDevice9 *mDevice; + IDirect3DDevice9Ex *mDeviceEx; // Might be null if D3D9Ex is not supported. + + // A pool of event queries that are currently unused. + std::vector<IDirect3DQuery9*> mEventQueryPool; + + VertexShaderCache mVertexShaderCache; + PixelShaderCache mPixelShaderCache; + + D3DCAPS9 mDeviceCaps; + D3DADAPTER_IDENTIFIER9 mAdapterIdentifier; + HWND mDeviceWindow; + + bool mSceneStarted; + EGLint mMaxSwapInterval; + EGLint mMinSwapInterval; + bool mSoftwareDevice; + bool mSupportsNonPower2Textures; + + typedef std::set<Surface*> SurfaceSet; + SurfaceSet mSurfaceSet; + + ConfigSet mConfigSet; + + typedef std::set<gl::Context*> ContextSet; + ContextSet mContextSet; + bool mDeviceLost; + + bool createDevice(); + void initializeDevice(); + bool resetDevice(); + + void initExtensionString(); + std::string mExtensionString; +}; +} + +#endif // LIBEGL_DISPLAY_H_ diff --git a/src/3rdparty/angle/src/libEGL/ShaderCache.h b/src/3rdparty/angle/src/libEGL/ShaderCache.h new file mode 100644 index 0000000000..cfe523ba09 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/ShaderCache.h @@ -0,0 +1,116 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Display.h: Defines egl::ShaderCache, a cache of Direct3D shader objects +// keyed by their byte code. + +#ifndef LIBEGL_SHADER_CACHE_H_ +#define LIBEGL_SHADER_CACHE_H_ + +#include <d3d9.h> + +#ifdef _MSC_VER +#include <hash_map> +#else +#include <unordered_map> +#endif + +namespace egl +{ +template <typename ShaderObject> +class ShaderCache +{ + public: + ShaderCache() : mDevice(NULL) + { + } + + ~ShaderCache() + { + // Call clear while the device is still valid. + ASSERT(mMap.empty()); + } + + void initialize(IDirect3DDevice9* device) + { + mDevice = device; + } + + ShaderObject *create(const DWORD *function, size_t length) + { + std::string key(reinterpret_cast<const char*>(function), length); + typename Map::iterator it = mMap.find(key); + if (it != mMap.end()) + { + it->second->AddRef(); + return it->second; + } + + ShaderObject *shader; + HRESULT result = createShader(function, &shader); + if (FAILED(result)) + { + return NULL; + } + + // Random eviction policy. + if (mMap.size() >= kMaxMapSize) + { + mMap.begin()->second->Release(); + mMap.erase(mMap.begin()); + } + + shader->AddRef(); + mMap[key] = shader; + + return shader; + } + + void clear() + { + for (typename Map::iterator it = mMap.begin(); it != mMap.end(); ++it) + { + it->second->Release(); + } + + mMap.clear(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ShaderCache); + + const static size_t kMaxMapSize = 100; + + HRESULT createShader(const DWORD *function, IDirect3DVertexShader9 **shader) + { + return mDevice->CreateVertexShader(function, shader); + } + + HRESULT createShader(const DWORD *function, IDirect3DPixelShader9 **shader) + { + return mDevice->CreatePixelShader(function, shader); + } + +#ifndef HASH_MAP +# ifdef _MSC_VER +# define HASH_MAP stdext::hash_map +# else +# define HASH_MAP std::unordered_map +# endif +#endif + + typedef HASH_MAP<std::string, ShaderObject*> Map; + Map mMap; + + IDirect3DDevice9 *mDevice; +}; + +typedef ShaderCache<IDirect3DVertexShader9> VertexShaderCache; +typedef ShaderCache<IDirect3DPixelShader9> PixelShaderCache; + +} + +#endif // LIBEGL_SHADER_CACHE_H_ diff --git a/src/3rdparty/angle/src/libEGL/Surface.cpp b/src/3rdparty/angle/src/libEGL/Surface.cpp new file mode 100644 index 0000000000..732c404b10 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/Surface.cpp @@ -0,0 +1,674 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Surface.cpp: Implements the egl::Surface class, representing a drawing surface +// such as the client area of a window, including any back buffers. +// Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3. + +#include <tchar.h> + +#include "libEGL/Surface.h" + +#include "common/debug.h" +#include "libGLESv2/Texture.h" + +#include "libEGL/main.h" +#include "libEGL/Display.h" + +#include <dwmapi.h> + +namespace egl +{ + +Surface::Surface(Display *display, const Config *config, HWND window, EGLint postSubBufferSupported) + : mDisplay(display), mConfig(config), mWindow(window), mPostSubBufferSupported(postSubBufferSupported) +{ + mSwapChain = NULL; + mBackBuffer = NULL; + mDepthStencil = NULL; + mRenderTarget = NULL; + mOffscreenTexture = NULL; + mShareHandle = NULL; + mTexture = NULL; + mTextureFormat = EGL_NO_TEXTURE; + mTextureTarget = EGL_NO_TEXTURE; + + mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio + mRenderBuffer = EGL_BACK_BUFFER; + mSwapBehavior = EGL_BUFFER_PRESERVED; + mSwapInterval = -1; + setSwapInterval(1); + + subclassWindow(); +} + +Surface::Surface(Display *display, const Config *config, HANDLE shareHandle, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureType) + : mDisplay(display), mWindow(NULL), mConfig(config), mShareHandle(shareHandle), mWidth(width), mHeight(height), mPostSubBufferSupported(EGL_FALSE) +{ + mSwapChain = NULL; + mBackBuffer = NULL; + mDepthStencil = NULL; + mRenderTarget = NULL; + mOffscreenTexture = NULL; + mWindowSubclassed = false; + mTexture = NULL; + mTextureFormat = textureFormat; + mTextureTarget = textureType; + + mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio + mRenderBuffer = EGL_BACK_BUFFER; + mSwapBehavior = EGL_BUFFER_PRESERVED; + mSwapInterval = -1; + setSwapInterval(1); +} + +Surface::~Surface() +{ + unsubclassWindow(); + release(); +} + +bool Surface::initialize() +{ + ASSERT(!mSwapChain && !mOffscreenTexture && !mDepthStencil); + + if (!resetSwapChain()) + return false; + + // Modify present parameters for this window, if we are composited, + // to minimize the amount of queuing done by DWM between our calls to + // present and the actual screen. + if (mWindow && (getComparableOSVersion() >= versionWindowsVista)) { + BOOL isComposited; + HRESULT result = DwmIsCompositionEnabled(&isComposited); + if (SUCCEEDED(result) && isComposited) { + DWM_PRESENT_PARAMETERS presentParams; + memset(&presentParams, 0, sizeof(presentParams)); + presentParams.cbSize = sizeof(DWM_PRESENT_PARAMETERS); + presentParams.cBuffer = 2; + + result = DwmSetPresentParameters(mWindow, &presentParams); + if (FAILED(result)) + ERR("Unable to set present parameters: 0x%08X", result); + } + } + + return true; +} + +void Surface::release() +{ + if (mSwapChain) + { + mSwapChain->Release(); + mSwapChain = NULL; + } + + if (mBackBuffer) + { + mBackBuffer->Release(); + mBackBuffer = NULL; + } + + if (mDepthStencil) + { + mDepthStencil->Release(); + mDepthStencil = NULL; + } + + if (mRenderTarget) + { + mRenderTarget->Release(); + mRenderTarget = NULL; + } + + if (mOffscreenTexture) + { + mOffscreenTexture->Release(); + mOffscreenTexture = NULL; + } + + if (mTexture) + { + mTexture->releaseTexImage(); + mTexture = NULL; + } + + mShareHandle = NULL; +} + +bool Surface::resetSwapChain() +{ + if (!mWindow) + { + return resetSwapChain(mWidth, mHeight); + } + + RECT windowRect; + if (!GetClientRect(getWindowHandle(), &windowRect)) + { + ASSERT(false); + + ERR("Could not retrieve the window dimensions"); + return false; + } + + return resetSwapChain(windowRect.right - windowRect.left, windowRect.bottom - windowRect.top); +} + +bool Surface::resetSwapChain(int backbufferWidth, int backbufferHeight) +{ + IDirect3DDevice9 *device = mDisplay->getDevice(); + + if (device == NULL) + { + return false; + } + + // Evict all non-render target textures to system memory and release all resources + // before reallocating them to free up as much video memory as possible. + device->EvictManagedResources(); + + HRESULT result; + + // Release specific resources to free up memory for the new render target, while the + // old render target still exists for the purpose of preserving its contents. + if (mSwapChain) + { + mSwapChain->Release(); + mSwapChain = NULL; + } + + if (mBackBuffer) + { + mBackBuffer->Release(); + mBackBuffer = NULL; + } + + if (mOffscreenTexture) + { + mOffscreenTexture->Release(); + mOffscreenTexture = NULL; + } + + if (mDepthStencil) + { + mDepthStencil->Release(); + mDepthStencil = NULL; + } + + mShareHandle = NULL; + HANDLE *pShareHandle = NULL; + if (!mWindow && mDisplay->shareHandleSupported()) + { + pShareHandle = &mShareHandle; + } + + result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET, + mConfig->mRenderTargetFormat, D3DPOOL_DEFAULT, &mOffscreenTexture, pShareHandle); + if (FAILED(result)) + { + ERR("Could not create offscreen texture: %08lX", result); + release(); + + if(isDeviceLostError(result)) + { + mDisplay->notifyDeviceLost(); + return false; + } + else + { + return error(EGL_BAD_ALLOC, false); + } + } + + IDirect3DSurface9 *oldRenderTarget = mRenderTarget; + + result = mOffscreenTexture->GetSurfaceLevel(0, &mRenderTarget); + ASSERT(SUCCEEDED(result)); + + if (oldRenderTarget) + { + RECT rect = + { + 0, 0, + mWidth, mHeight + }; + + if (rect.right > static_cast<LONG>(backbufferWidth)) + { + rect.right = backbufferWidth; + } + + if (rect.bottom > static_cast<LONG>(backbufferHeight)) + { + rect.bottom = backbufferHeight; + } + + mDisplay->endScene(); + + result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE); + ASSERT(SUCCEEDED(result)); + + oldRenderTarget->Release(); + } + + if (mWindow) + { + D3DPRESENT_PARAMETERS presentParameters = {0}; + presentParameters.AutoDepthStencilFormat = mConfig->mDepthStencilFormat; + presentParameters.BackBufferCount = 1; + presentParameters.BackBufferFormat = mConfig->mRenderTargetFormat; + presentParameters.EnableAutoDepthStencil = FALSE; + presentParameters.Flags = 0; + presentParameters.hDeviceWindow = getWindowHandle(); + presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented + presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented + presentParameters.PresentationInterval = mPresentInterval; + presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; + presentParameters.Windowed = TRUE; + presentParameters.BackBufferWidth = backbufferWidth; + presentParameters.BackBufferHeight = backbufferHeight; + + // http://crbug.com/140239 + // http://crbug.com/143434 + // + // Some AMD/Intel switchable systems / drivers appear to round swap chain surfaces to a multiple of 64 pixels in width + // when using the integrated Intel. This rounds the width up rather than down. + // + // Some non-switchable AMD GPUs / drivers do not respect the source rectangle to Present. Therefore, when the vendor ID + // is not Intel, the back buffer width must be exactly the same width as the window or horizontal scaling will occur. + D3DADAPTER_IDENTIFIER9* adapterIdentifier = mDisplay->getAdapterIdentifier(); + if (adapterIdentifier->VendorId == VENDOR_ID_INTEL) + { + presentParameters.BackBufferWidth = (presentParameters.BackBufferWidth + 63) / 64 * 64; + } + + result = device->CreateAdditionalSwapChain(&presentParameters, &mSwapChain); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL || result == D3DERR_DEVICELOST); + + ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result); + release(); + + if(isDeviceLostError(result)) + { + mDisplay->notifyDeviceLost(); + return false; + } + else + { + return error(EGL_BAD_ALLOC, false); + } + } + + result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer); + ASSERT(SUCCEEDED(result)); + } + + if (mConfig->mDepthStencilFormat != D3DFMT_UNKNOWN) + { + result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight, mConfig->mDepthStencilFormat, D3DMULTISAMPLE_NONE, + 0, FALSE, &mDepthStencil, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL); + + ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result); + release(); + + if(isDeviceLostError(result)) + { + mDisplay->notifyDeviceLost(); + return false; + } + else + { + return error(EGL_BAD_ALLOC, false); + } + } + } + + mWidth = backbufferWidth; + mHeight = backbufferHeight; + + mPresentIntervalDirty = false; + return true; +} + +bool Surface::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +{ + if (!mSwapChain) + { + return true; + } + + if (x + width > mWidth) + { + width = mWidth - x; + } + + if (y + height > mHeight) + { + height = mHeight - y; + } + + if (width == 0 || height == 0) + { + return true; + } + + IDirect3DDevice9 *device = mDisplay->getDevice(); + + // Disable all pipeline operations + device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + device->SetRenderState(D3DRS_STENCILENABLE, FALSE); + device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); + device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE); + device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + device->SetPixelShader(NULL); + device->SetVertexShader(NULL); + + device->SetRenderTarget(0, mBackBuffer); + device->SetDepthStencilSurface(NULL); + + device->SetTexture(0, mOffscreenTexture); + device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + + D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f}; + device->SetViewport(&viewport); + + float x1 = x - 0.5f; + float y1 = (mHeight - y - height) - 0.5f; + float x2 = (x + width) - 0.5f; + float y2 = (mHeight - y) - 0.5f; + + float u1 = x / float(mWidth); + float v1 = y / float(mHeight); + float u2 = (x + width) / float(mWidth); + float v2 = (y + height) / float(mHeight); + + float quad[4][6] = {{x1, y1, 0.0f, 1.0f, u1, v2}, + {x2, y1, 0.0f, 1.0f, u2, v2}, + {x2, y2, 0.0f, 1.0f, u2, v1}, + {x1, y2, 0.0f, 1.0f, u1, v1}}; // x, y, z, rhw, u, v + + mDisplay->startScene(); + device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float)); + mDisplay->endScene(); + + device->SetTexture(0, NULL); + + RECT rect = + { + x, mHeight - y - height, + x + width, mHeight - y + }; + + HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0); + + gl::Context *context = static_cast<gl::Context*>(glGetCurrentContext()); + if (context) + { + context->markAllStateDirty(); + } + + if (isDeviceLostError(result)) + { + mDisplay->notifyDeviceLost(); + return false; + } + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR) + { + return error(EGL_BAD_ALLOC, false); + } + + ASSERT(SUCCEEDED(result)); + + checkForOutOfDateSwapChain(); + + return true; +} + +HWND Surface::getWindowHandle() +{ + return mWindow; +} + + +#define kSurfaceProperty _TEXT("Egl::SurfaceOwner") +#define kParentWndProc _TEXT("Egl::SurfaceParentWndProc") + +static LRESULT CALLBACK SurfaceWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + if (message == WM_SIZE) + { + Surface* surf = reinterpret_cast<Surface*>(GetProp(hwnd, kSurfaceProperty)); + if(surf) + { + surf->checkForOutOfDateSwapChain(); + } + } + WNDPROC prevWndFunc = reinterpret_cast<WNDPROC >(GetProp(hwnd, kParentWndProc)); + return CallWindowProc(prevWndFunc, hwnd, message, wparam, lparam); +} + +void Surface::subclassWindow() +{ + if (!mWindow) + { + return; + } + + DWORD processId; + DWORD threadId = GetWindowThreadProcessId(mWindow, &processId); + if (processId != GetCurrentProcessId() || threadId != GetCurrentThreadId()) + { + return; + } + + SetLastError(0); + LONG_PTR oldWndProc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(SurfaceWindowProc)); + if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS) + { + mWindowSubclassed = false; + return; + } + + SetProp(mWindow, kSurfaceProperty, reinterpret_cast<HANDLE>(this)); + SetProp(mWindow, kParentWndProc, reinterpret_cast<HANDLE>(oldWndProc)); + mWindowSubclassed = true; +} + +void Surface::unsubclassWindow() +{ + if(!mWindowSubclassed) + { + return; + } + + // un-subclass + LONG_PTR parentWndFunc = reinterpret_cast<LONG_PTR>(GetProp(mWindow, kParentWndProc)); + + // Check the windowproc is still SurfaceWindowProc. + // If this assert fails, then it is likely the application has subclassed the + // hwnd as well and did not unsubclass before destroying its EGL context. The + // application should be modified to either subclass before initializing the + // EGL context, or to unsubclass before destroying the EGL context. + if(parentWndFunc) + { + LONG_PTR prevWndFunc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, parentWndFunc); + ASSERT(prevWndFunc == reinterpret_cast<LONG_PTR>(SurfaceWindowProc)); + } + + RemoveProp(mWindow, kSurfaceProperty); + RemoveProp(mWindow, kParentWndProc); + mWindowSubclassed = false; +} + +bool Surface::checkForOutOfDateSwapChain() +{ + RECT client; + if (!GetClientRect(getWindowHandle(), &client)) + { + ASSERT(false); + return false; + } + + // Grow the buffer now, if the window has grown. We need to grow now to avoid losing information. + int clientWidth = client.right - client.left; + int clientHeight = client.bottom - client.top; + bool sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); + + if (sizeDirty || mPresentIntervalDirty) + { + resetSwapChain(clientWidth, clientHeight); + if (static_cast<egl::Surface*>(getCurrentDrawSurface()) == this) + { + glMakeCurrent(glGetCurrentContext(), static_cast<egl::Display*>(getCurrentDisplay()), this); + } + + return true; + } + return false; +} + +DWORD Surface::convertInterval(EGLint interval) +{ + switch(interval) + { + case 0: return D3DPRESENT_INTERVAL_IMMEDIATE; + case 1: return D3DPRESENT_INTERVAL_ONE; + case 2: return D3DPRESENT_INTERVAL_TWO; + case 3: return D3DPRESENT_INTERVAL_THREE; + case 4: return D3DPRESENT_INTERVAL_FOUR; + default: UNREACHABLE(); + } + + return D3DPRESENT_INTERVAL_DEFAULT; +} + +bool Surface::swap() +{ + return swapRect(0, 0, mWidth, mHeight); +} + +bool Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +{ + if (!mPostSubBufferSupported) + { + // Spec is not clear about how this should be handled. + return true; + } + + return swapRect(x, y, width, height); +} + +EGLint Surface::getWidth() const +{ + return mWidth; +} + +EGLint Surface::getHeight() const +{ + return mHeight; +} + +EGLint Surface::isPostSubBufferSupported() const +{ + return mPostSubBufferSupported; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Surface::getRenderTarget() +{ + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + + return mRenderTarget; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Surface::getDepthStencil() +{ + if (mDepthStencil) + { + mDepthStencil->AddRef(); + } + + return mDepthStencil; +} + +IDirect3DTexture9 *Surface::getOffscreenTexture() +{ + if (mOffscreenTexture) + { + mOffscreenTexture->AddRef(); + } + + return mOffscreenTexture; +} + +void Surface::setSwapInterval(EGLint interval) +{ + if (mSwapInterval == interval) + { + return; + } + + mSwapInterval = interval; + mSwapInterval = std::max(mSwapInterval, mDisplay->getMinSwapInterval()); + mSwapInterval = std::min(mSwapInterval, mDisplay->getMaxSwapInterval()); + + mPresentInterval = convertInterval(mSwapInterval); + mPresentIntervalDirty = true; +} + +EGLenum Surface::getTextureFormat() const +{ + return mTextureFormat; +} + +EGLenum Surface::getTextureTarget() const +{ + return mTextureTarget; +} + +void Surface::setBoundTexture(gl::Texture2D *texture) +{ + mTexture = texture; +} + +gl::Texture2D *Surface::getBoundTexture() const +{ + return mTexture; +} + +D3DFORMAT Surface::getFormat() const +{ + return mConfig->mRenderTargetFormat; +} +} diff --git a/src/3rdparty/angle/src/libEGL/Surface.h b/src/3rdparty/angle/src/libEGL/Surface.h new file mode 100644 index 0000000000..40bd7028ab --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/Surface.h @@ -0,0 +1,112 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Surface.h: Defines the egl::Surface class, representing a drawing surface +// such as the client area of a window, including any back buffers. +// Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3. + +#ifndef INCLUDE_SURFACE_H_ +#define INCLUDE_SURFACE_H_ + +#define EGLAPI +#include <EGL/egl.h> +#include <d3d9.h> + +#include "common/angleutils.h" + +namespace gl +{ +class Texture2D; +} + +namespace egl +{ +class Display; +class Config; + +class Surface +{ + public: + Surface(Display *display, const egl::Config *config, HWND window, EGLint postSubBufferSupported); + Surface(Display *display, const egl::Config *config, HANDLE shareHandle, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureTarget); + + ~Surface(); + + bool initialize(); + void release(); + bool resetSwapChain(); + + HWND getWindowHandle(); + bool swap(); + bool postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height); + + virtual EGLint getWidth() const; + virtual EGLint getHeight() const; + + virtual EGLint isPostSubBufferSupported() const; + + virtual IDirect3DSurface9 *getRenderTarget(); + virtual IDirect3DSurface9 *getDepthStencil(); + virtual IDirect3DTexture9 *getOffscreenTexture(); + + HANDLE getShareHandle() { return mShareHandle; } + + void setSwapInterval(EGLint interval); + bool checkForOutOfDateSwapChain(); // Returns true if swapchain changed due to resize or interval update + + virtual EGLenum getTextureFormat() const; + virtual EGLenum getTextureTarget() const; + virtual D3DFORMAT getFormat() const; + + virtual void setBoundTexture(gl::Texture2D *texture); + virtual gl::Texture2D *getBoundTexture() const; + +private: + DISALLOW_COPY_AND_ASSIGN(Surface); + + Display *const mDisplay; + IDirect3DSwapChain9 *mSwapChain; + IDirect3DSurface9 *mBackBuffer; + IDirect3DSurface9 *mDepthStencil; + IDirect3DSurface9* mRenderTarget; + IDirect3DTexture9* mOffscreenTexture; + + HANDLE mShareHandle; + + void subclassWindow(); + void unsubclassWindow(); + bool resetSwapChain(int backbufferWidth, int backbufferHeight); + bool swapRect(EGLint x, EGLint y, EGLint width, EGLint height); + static DWORD convertInterval(EGLint interval); + + const HWND mWindow; // Window that the surface is created for. + bool mWindowSubclassed; // Indicates whether we successfully subclassed mWindow for WM_RESIZE hooking + const egl::Config *mConfig; // EGL config surface was created with + EGLint mHeight; // Height of surface + EGLint mWidth; // Width of surface +// EGLint horizontalResolution; // Horizontal dot pitch +// EGLint verticalResolution; // Vertical dot pitch +// EGLBoolean largestPBuffer; // If true, create largest pbuffer possible +// EGLBoolean mipmapTexture; // True if texture has mipmaps +// EGLint mipmapLevel; // Mipmap level to render to +// EGLenum multisampleResolve; // Multisample resolve behavior + EGLint mPixelAspectRatio; // Display aspect ratio + EGLenum mRenderBuffer; // Render buffer + EGLenum mSwapBehavior; // Buffer swap behavior + EGLenum mTextureFormat; // Format of texture: RGB, RGBA, or no texture + EGLenum mTextureTarget; // Type of texture: 2D or no texture +// EGLenum vgAlphaFormat; // Alpha format for OpenVG +// EGLenum vgColorSpace; // Color space for OpenVG + EGLint mSwapInterval; + EGLint mPostSubBufferSupported; + + DWORD mPresentInterval; + bool mPresentIntervalDirty; + gl::Texture2D *mTexture; +}; +} + +#endif // INCLUDE_SURFACE_H_ diff --git a/src/3rdparty/angle/src/libEGL/libEGL.cpp b/src/3rdparty/angle/src/libEGL/libEGL.cpp new file mode 100644 index 0000000000..25df1c8c24 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/libEGL.cpp @@ -0,0 +1,1181 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// libEGL.cpp: Implements the exported EGL functions. + +#include <exception> + +#include "common/debug.h" +#include "common/version.h" +#include "libGLESv2/Context.h" +#include "libGLESv2/Texture.h" + +#include "libEGL/main.h" +#include "libEGL/Display.h" + + +bool validateDisplay(egl::Display *display) +{ + if (display == EGL_NO_DISPLAY) + { + return error(EGL_BAD_DISPLAY, false); + } + + if (!display->isInitialized()) + { + return error(EGL_NOT_INITIALIZED, false); + } + + return true; +} + +bool validateConfig(egl::Display *display, EGLConfig config) +{ + if (!validateDisplay(display)) + { + return false; + } + + if (!display->isValidConfig(config)) + { + return error(EGL_BAD_CONFIG, false); + } + + return true; +} + +bool validateContext(egl::Display *display, gl::Context *context) +{ + if (!validateDisplay(display)) + { + return false; + } + + if (!display->isValidContext(context)) + { + return error(EGL_BAD_CONTEXT, false); + } + + return true; +} + +bool validateSurface(egl::Display *display, egl::Surface *surface) +{ + if (!validateDisplay(display)) + { + return false; + } + + if (!display->isValidSurface(surface)) + { + return error(EGL_BAD_SURFACE, false); + } + + return true; +} + +extern "C" +{ +EGLint __stdcall eglGetError(void) +{ + EVENT("()"); + + EGLint error = egl::getCurrentError(); + + if (error != EGL_SUCCESS) + { + egl::setCurrentError(EGL_SUCCESS); + } + + return error; +} + +EGLDisplay __stdcall eglGetDisplay(EGLNativeDisplayType display_id) +{ + EVENT("(EGLNativeDisplayType display_id = 0x%0.8p)", display_id); + + try + { + return egl::Display::getDisplay(display_id); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_DISPLAY); + } +} + +EGLBoolean __stdcall eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint *major = 0x%0.8p, EGLint *minor = 0x%0.8p)", + dpy, major, minor); + + try + { + if (dpy == EGL_NO_DISPLAY) + { + return error(EGL_BAD_DISPLAY, EGL_FALSE); + } + + egl::Display *display = static_cast<egl::Display*>(dpy); + + if (!display->initialize()) + { + return error(EGL_NOT_INITIALIZED, EGL_FALSE); + } + + if (major) *major = 1; + if (minor) *minor = 4; + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglTerminate(EGLDisplay dpy) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p)", dpy); + + try + { + if (dpy == EGL_NO_DISPLAY) + { + return error(EGL_BAD_DISPLAY, EGL_FALSE); + } + + egl::Display *display = static_cast<egl::Display*>(dpy); + + display->terminate(); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +const char *__stdcall eglQueryString(EGLDisplay dpy, EGLint name) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint name = %d)", dpy, name); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + + if (!validateDisplay(display)) + { + return NULL; + } + + switch (name) + { + case EGL_CLIENT_APIS: + return success("OpenGL_ES"); + case EGL_EXTENSIONS: + return display->getExtensionString(); + case EGL_VENDOR: + return success("Google Inc."); + case EGL_VERSION: + return success("1.4 (ANGLE " VERSION_STRING ")"); + } + + return error(EGL_BAD_PARAMETER, (const char*)NULL); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, (const char*)NULL); + } +} + +EGLBoolean __stdcall eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig *configs = 0x%0.8p, " + "EGLint config_size = %d, EGLint *num_config = 0x%0.8p)", + dpy, configs, config_size, num_config); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + + if (!validateDisplay(display)) + { + return EGL_FALSE; + } + + if (!num_config) + { + return error(EGL_BAD_PARAMETER, EGL_FALSE); + } + + const EGLint attribList[] = {EGL_NONE}; + + if (!display->getConfigs(configs, attribList, config_size, num_config)) + { + return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); + } + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p, " + "EGLConfig *configs = 0x%0.8p, EGLint config_size = %d, EGLint *num_config = 0x%0.8p)", + dpy, attrib_list, configs, config_size, num_config); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + + if (!validateDisplay(display)) + { + return EGL_FALSE; + } + + if (!num_config) + { + return error(EGL_BAD_PARAMETER, EGL_FALSE); + } + + const EGLint attribList[] = {EGL_NONE}; + + if (!attrib_list) + { + attrib_list = attribList; + } + + display->getConfigs(configs, attrib_list, config_size, num_config); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)", + dpy, config, attribute, value); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + + if (!validateConfig(display, config)) + { + return EGL_FALSE; + } + + if (!display->getConfigAttrib(config, attribute, value)) + { + return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); + } + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLSurface __stdcall eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativeWindowType win = 0x%0.8p, " + "const EGLint *attrib_list = 0x%0.8p)", dpy, config, win, attrib_list); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + + if (!validateConfig(display, config)) + { + return EGL_NO_SURFACE; + } + + HWND window = (HWND)win; + + if (!IsWindow(window)) + { + return error(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); + } + + return display->createWindowSurface(window, config, attrib_list); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } +} + +EGLSurface __stdcall eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p)", + dpy, config, attrib_list); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + + if (!validateConfig(display, config)) + { + return EGL_NO_SURFACE; + } + + return display->createOffscreenSurface(config, NULL, attrib_list); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } +} + +EGLSurface __stdcall eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativePixmapType pixmap = 0x%0.8p, " + "const EGLint *attrib_list = 0x%0.8p)", dpy, config, pixmap, attrib_list); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + + if (!validateConfig(display, config)) + { + return EGL_NO_SURFACE; + } + + UNIMPLEMENTED(); // FIXME + + return success(EGL_NO_SURFACE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } +} + +EGLBoolean __stdcall eglDestroySurface(EGLDisplay dpy, EGLSurface surface) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + egl::Surface *eglSurface = static_cast<egl::Surface*>(surface); + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + if (surface == EGL_NO_SURFACE) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + display->destroySurface((egl::Surface*)surface); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)", + dpy, surface, attribute, value); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + egl::Surface *eglSurface = (egl::Surface*)surface; + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + if (surface == EGL_NO_SURFACE) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + switch (attribute) + { + case EGL_VG_ALPHA_FORMAT: + UNIMPLEMENTED(); // FIXME + break; + case EGL_VG_COLORSPACE: + UNIMPLEMENTED(); // FIXME + break; + case EGL_CONFIG_ID: + UNIMPLEMENTED(); // FIXME + break; + case EGL_HEIGHT: + *value = eglSurface->getHeight(); + break; + case EGL_HORIZONTAL_RESOLUTION: + UNIMPLEMENTED(); // FIXME + break; + case EGL_LARGEST_PBUFFER: + UNIMPLEMENTED(); // FIXME + break; + case EGL_MIPMAP_TEXTURE: + UNIMPLEMENTED(); // FIXME + break; + case EGL_MIPMAP_LEVEL: + UNIMPLEMENTED(); // FIXME + break; + case EGL_MULTISAMPLE_RESOLVE: + UNIMPLEMENTED(); // FIXME + break; + case EGL_PIXEL_ASPECT_RATIO: + UNIMPLEMENTED(); // FIXME + break; + case EGL_RENDER_BUFFER: + UNIMPLEMENTED(); // FIXME + break; + case EGL_SWAP_BEHAVIOR: + UNIMPLEMENTED(); // FIXME + break; + case EGL_TEXTURE_FORMAT: + UNIMPLEMENTED(); // FIXME + break; + case EGL_TEXTURE_TARGET: + UNIMPLEMENTED(); // FIXME + break; + case EGL_VERTICAL_RESOLUTION: + UNIMPLEMENTED(); // FIXME + break; + case EGL_WIDTH: + *value = eglSurface->getWidth(); + break; + case EGL_POST_SUB_BUFFER_SUPPORTED_NV: + *value = eglSurface->isPostSubBufferSupported(); + break; + default: + return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); + } + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value) +{ + TRACE("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, void **value = 0x%0.8p)", + dpy, surface, attribute, value); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + egl::Surface *eglSurface = (egl::Surface*)surface; + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + if (surface == EGL_NO_SURFACE) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + switch (attribute) + { + case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: + *value = (void*) eglSurface->getShareHandle(); + break; + default: + return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); + } + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglBindAPI(EGLenum api) +{ + EVENT("(EGLenum api = 0x%X)", api); + + try + { + switch (api) + { + case EGL_OPENGL_API: + case EGL_OPENVG_API: + return error(EGL_BAD_PARAMETER, EGL_FALSE); // Not supported by this implementation + case EGL_OPENGL_ES_API: + break; + default: + return error(EGL_BAD_PARAMETER, EGL_FALSE); + } + + egl::setCurrentAPI(api); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLenum __stdcall eglQueryAPI(void) +{ + EVENT("()"); + + try + { + EGLenum API = egl::getCurrentAPI(); + + return success(API); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglWaitClient(void) +{ + EVENT("()"); + + try + { + UNIMPLEMENTED(); // FIXME + + return success(0); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglReleaseThread(void) +{ + EVENT("()"); + + try + { + eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLSurface __stdcall eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLenum buftype = 0x%X, EGLClientBuffer buffer = 0x%0.8p, " + "EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p)", + dpy, buftype, buffer, config, attrib_list); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + + if (!validateConfig(display, config)) + { + return EGL_NO_SURFACE; + } + + if (buftype != EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE || !buffer) + { + return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); + } + + return display->createOffscreenSurface(config, (HANDLE)buffer, attrib_list); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } +} + +EGLBoolean __stdcall eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint value = %d)", + dpy, surface, attribute, value); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + egl::Surface *eglSurface = static_cast<egl::Surface*>(surface); + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + UNIMPLEMENTED(); // FIXME + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + egl::Surface *eglSurface = static_cast<egl::Surface*>(surface); + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + if (buffer != EGL_BACK_BUFFER) + { + return error(EGL_BAD_PARAMETER, EGL_FALSE); + } + + if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle()) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + if (eglSurface->getBoundTexture()) + { + return error(EGL_BAD_ACCESS, EGL_FALSE); + } + + if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE) + { + return error(EGL_BAD_MATCH, EGL_FALSE); + } + + if (!glBindTexImage(eglSurface)) + { + return error(EGL_BAD_MATCH, EGL_FALSE); + } + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + egl::Surface *eglSurface = static_cast<egl::Surface*>(surface); + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + if (buffer != EGL_BACK_BUFFER) + { + return error(EGL_BAD_PARAMETER, EGL_FALSE); + } + + if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle()) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE) + { + return error(EGL_BAD_MATCH, EGL_FALSE); + } + + gl::Texture2D *texture = eglSurface->getBoundTexture(); + + if (texture) + { + texture->releaseTexImage(); + } + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglSwapInterval(EGLDisplay dpy, EGLint interval) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint interval = %d)", dpy, interval); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + + if (!validateDisplay(display)) + { + return EGL_FALSE; + } + + egl::Surface *draw_surface = static_cast<egl::Surface*>(egl::getCurrentDrawSurface()); + + if (draw_surface == NULL) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + draw_surface->setSwapInterval(interval); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLContext __stdcall eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLContext share_context = 0x%0.8p, " + "const EGLint *attrib_list = 0x%0.8p)", dpy, config, share_context, attrib_list); + + try + { + // Get the requested client version (default is 1) and check it is two. + EGLint client_version = 1; + bool reset_notification = false; + bool robust_access = false; + + if (attrib_list) + { + for (const EGLint* attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2) + { + switch (attribute[0]) + { + case EGL_CONTEXT_CLIENT_VERSION: + client_version = attribute[1]; + break; + case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT: + if (attribute[1] == EGL_TRUE) + { + return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT); // Unimplemented + // robust_access = true; + } + else if (attribute[1] != EGL_FALSE) + return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); + break; + case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT: + if (attribute[1] == EGL_LOSE_CONTEXT_ON_RESET_EXT) + reset_notification = true; + else if (attribute[1] != EGL_NO_RESET_NOTIFICATION_EXT) + return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); + break; + default: + return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); + } + } + } + + if (client_version != 2) + { + return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT); + } + + if (share_context && static_cast<gl::Context*>(share_context)->isResetNotificationEnabled() != reset_notification) + { + return error(EGL_BAD_MATCH, EGL_NO_CONTEXT); + } + + egl::Display *display = static_cast<egl::Display*>(dpy); + + if (!validateConfig(display, config)) + { + return EGL_NO_CONTEXT; + } + + EGLContext context = display->createContext(config, static_cast<gl::Context*>(share_context), reset_notification, robust_access); + + if (context) + return success(context); + else + return error(EGL_CONTEXT_LOST, EGL_NO_CONTEXT); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT); + } +} + +EGLBoolean __stdcall eglDestroyContext(EGLDisplay dpy, EGLContext ctx) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p)", dpy, ctx); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + gl::Context *context = static_cast<gl::Context*>(ctx); + + if (!validateContext(display, context)) + { + return EGL_FALSE; + } + + if (ctx == EGL_NO_CONTEXT) + { + return error(EGL_BAD_CONTEXT, EGL_FALSE); + } + + display->destroyContext(context); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface draw = 0x%0.8p, EGLSurface read = 0x%0.8p, EGLContext ctx = 0x%0.8p)", + dpy, draw, read, ctx); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + gl::Context *context = static_cast<gl::Context*>(ctx); + IDirect3DDevice9 *device = display->getDevice(); + + if (!device || display->testDeviceLost()) + { + display->notifyDeviceLost(); + return EGL_FALSE; + } + + if (display->isDeviceLost()) + { + return error(EGL_CONTEXT_LOST, EGL_FALSE); + } + + if (ctx != EGL_NO_CONTEXT && !validateContext(display, context)) + { + return EGL_FALSE; + } + + if ((draw != EGL_NO_SURFACE && !validateSurface(display, static_cast<egl::Surface*>(draw))) || + (read != EGL_NO_SURFACE && !validateSurface(display, static_cast<egl::Surface*>(read)))) + { + return EGL_FALSE; + } + + if (draw != read) + { + UNIMPLEMENTED(); // FIXME + } + + egl::setCurrentDisplay(dpy); + egl::setCurrentDrawSurface(draw); + egl::setCurrentReadSurface(read); + + glMakeCurrent(context, display, static_cast<egl::Surface*>(draw)); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLContext __stdcall eglGetCurrentContext(void) +{ + EVENT("()"); + + try + { + EGLContext context = glGetCurrentContext(); + + return success(context); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT); + } +} + +EGLSurface __stdcall eglGetCurrentSurface(EGLint readdraw) +{ + EVENT("(EGLint readdraw = %d)", readdraw); + + try + { + if (readdraw == EGL_READ) + { + EGLSurface read = egl::getCurrentReadSurface(); + return success(read); + } + else if (readdraw == EGL_DRAW) + { + EGLSurface draw = egl::getCurrentDrawSurface(); + return success(draw); + } + else + { + return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); + } + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } +} + +EGLDisplay __stdcall eglGetCurrentDisplay(void) +{ + EVENT("()"); + + try + { + EGLDisplay dpy = egl::getCurrentDisplay(); + + return success(dpy); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_DISPLAY); + } +} + +EGLBoolean __stdcall eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)", + dpy, ctx, attribute, value); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + gl::Context *context = static_cast<gl::Context*>(ctx); + + if (!validateContext(display, context)) + { + return EGL_FALSE; + } + + UNIMPLEMENTED(); // FIXME + + return success(0); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglWaitGL(void) +{ + EVENT("()"); + + try + { + UNIMPLEMENTED(); // FIXME + + return success(0); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglWaitNative(EGLint engine) +{ + EVENT("(EGLint engine = %d)", engine); + + try + { + UNIMPLEMENTED(); // FIXME + + return success(0); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + egl::Surface *eglSurface = (egl::Surface*)surface; + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + if (display->isDeviceLost()) + { + return error(EGL_CONTEXT_LOST, EGL_FALSE); + } + + if (surface == EGL_NO_SURFACE) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + if (eglSurface->swap()) + { + return success(EGL_TRUE); + } + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLBoolean __stdcall eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLNativePixmapType target = 0x%0.8p)", dpy, surface, target); + + try + { + egl::Display *display = static_cast<egl::Display*>(dpy); + egl::Surface *eglSurface = static_cast<egl::Surface*>(surface); + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + if (display->isDeviceLost()) + { + return error(EGL_CONTEXT_LOST, EGL_FALSE); + } + + UNIMPLEMENTED(); // FIXME + + return success(0); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglPostSubBufferNV(EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint x = %d, EGLint y = %d, EGLint width = %d, EGLint height = %d)", dpy, surface, x, y, width, height); + + try + { + if (x < 0 || y < 0 || width < 0 || height < 0) + { + return error(EGL_BAD_PARAMETER, EGL_FALSE); + } + + egl::Display *display = static_cast<egl::Display*>(dpy); + egl::Surface *eglSurface = static_cast<egl::Surface*>(surface); + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + if (display->isDeviceLost()) + { + return error(EGL_CONTEXT_LOST, EGL_FALSE); + } + + if (surface == EGL_NO_SURFACE) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + if (eglSurface->postSubBuffer(x, y, width, height)) + { + return success(EGL_TRUE); + } + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +__eglMustCastToProperFunctionPointerType __stdcall eglGetProcAddress(const char *procname) +{ + EVENT("(const char *procname = \"%s\")", procname); + + try + { + struct Extension + { + const char *name; + __eglMustCastToProperFunctionPointerType address; + }; + + static const Extension eglExtensions[] = + { + {"eglQuerySurfacePointerANGLE", (__eglMustCastToProperFunctionPointerType)eglQuerySurfacePointerANGLE}, + {"eglPostSubBufferNV", (__eglMustCastToProperFunctionPointerType)eglPostSubBufferNV}, + {"", NULL}, + }; + + for (int ext = 0; ext < sizeof(eglExtensions) / sizeof(Extension); ext++) + { + if (strcmp(procname, eglExtensions[ext].name) == 0) + { + return (__eglMustCastToProperFunctionPointerType)eglExtensions[ext].address; + } + } + + return glGetProcAddress(procname); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, (__eglMustCastToProperFunctionPointerType)NULL); + } +} +} diff --git a/src/3rdparty/angle/src/libEGL/libEGL.def b/src/3rdparty/angle/src/libEGL/libEGL.def new file mode 100644 index 0000000000..71a5e67977 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/libEGL.def @@ -0,0 +1,36 @@ +LIBRARY libEGL +EXPORTS + eglBindAPI @14 + eglBindTexImage @20 + eglChooseConfig @7 + eglCopyBuffers @33 + eglCreateContext @23 + eglCreatePbufferFromClientBuffer @18 + eglCreatePbufferSurface @10 + eglCreatePixmapSurface @11 + eglCreateWindowSurface @9 + eglDestroyContext @24 + eglDestroySurface @12 + eglGetConfigAttrib @8 + eglGetConfigs @6 + eglGetCurrentContext @26 + eglGetCurrentDisplay @28 + eglGetCurrentSurface @27 + eglGetDisplay @2 + eglGetError @1 + eglGetProcAddress @34 + eglInitialize @3 + eglMakeCurrent @25 + eglQueryAPI @15 + eglQueryContext @29 + eglQueryString @5 + eglQuerySurface @13 + eglReleaseTexImage @21 + eglReleaseThread @17 + eglSurfaceAttrib @19 + eglSwapBuffers @32 + eglSwapInterval @22 + eglTerminate @4 + eglWaitClient @16 + eglWaitGL @30 + eglWaitNative @31
\ No newline at end of file diff --git a/src/3rdparty/angle/src/libEGL/libEGL.rc b/src/3rdparty/angle/src/libEGL/libEGL.rc new file mode 100644 index 0000000000..5d1f32f1c9 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/libEGL.rc @@ -0,0 +1,102 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include <windows.h> +#include "../common/version.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "#include ""../common/version.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION + PRODUCTVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "ANGLE libEGL Dynamic Link Library" + VALUE "FileVersion", VERSION_STRING + VALUE "InternalName", "libEGL" + VALUE "LegalCopyright", "Copyright (C) 2011 Google Inc." + VALUE "OriginalFilename", "libEGL.dll" + VALUE "PrivateBuild", VERSION_STRING + VALUE "ProductName", "ANGLE libEGL Dynamic Link Library" + VALUE "ProductVersion", VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/src/3rdparty/angle/src/libEGL/main.cpp b/src/3rdparty/angle/src/libEGL/main.cpp new file mode 100644 index 0000000000..dc24c4fb04 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/main.cpp @@ -0,0 +1,165 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// main.cpp: DLL entry point and management of thread-local data. + +#include "libEGL/main.h" + +#include "common/debug.h" + +static DWORD currentTLS = TLS_OUT_OF_INDEXES; + +extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + { +#if !defined(ANGLE_DISABLE_TRACE) + FILE *debug = fopen(TRACE_OUTPUT_FILE, "rt"); + + if (debug) + { + fclose(debug); + debug = fopen(TRACE_OUTPUT_FILE, "wt"); // Erase + + if (debug) + { + fclose(debug); + } + } +#endif + + currentTLS = TlsAlloc(); + + if (currentTLS == TLS_OUT_OF_INDEXES) + { + return FALSE; + } + } + // Fall throught to initialize index + case DLL_THREAD_ATTACH: + { + egl::Current *current = (egl::Current*)LocalAlloc(LPTR, sizeof(egl::Current)); + + if (current) + { + TlsSetValue(currentTLS, current); + + current->error = EGL_SUCCESS; + current->API = EGL_OPENGL_ES_API; + current->display = EGL_NO_DISPLAY; + current->drawSurface = EGL_NO_SURFACE; + current->readSurface = EGL_NO_SURFACE; + } + } + break; + case DLL_THREAD_DETACH: + { + void *current = TlsGetValue(currentTLS); + + if (current) + { + LocalFree((HLOCAL)current); + } + } + break; + case DLL_PROCESS_DETACH: + { + void *current = TlsGetValue(currentTLS); + + if (current) + { + LocalFree((HLOCAL)current); + } + + TlsFree(currentTLS); + } + break; + default: + break; + } + + return TRUE; +} + +namespace egl +{ +void setCurrentError(EGLint error) +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + current->error = error; +} + +EGLint getCurrentError() +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + return current->error; +} + +void setCurrentAPI(EGLenum API) +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + current->API = API; +} + +EGLenum getCurrentAPI() +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + return current->API; +} + +void setCurrentDisplay(EGLDisplay dpy) +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + current->display = dpy; +} + +EGLDisplay getCurrentDisplay() +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + return current->display; +} + +void setCurrentDrawSurface(EGLSurface surface) +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + current->drawSurface = surface; +} + +EGLSurface getCurrentDrawSurface() +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + return current->drawSurface; +} + +void setCurrentReadSurface(EGLSurface surface) +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + current->readSurface = surface; +} + +EGLSurface getCurrentReadSurface() +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + return current->readSurface; +} +} + +void error(EGLint errorCode) +{ + egl::setCurrentError(errorCode); +} diff --git a/src/3rdparty/angle/src/libEGL/main.h b/src/3rdparty/angle/src/libEGL/main.h new file mode 100644 index 0000000000..d09d9e6bc3 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/main.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// main.h: Management of thread-local data. + +#ifndef LIBEGL_MAIN_H_ +#define LIBEGL_MAIN_H_ + +#define EGLAPI +#include <EGL/egl.h> +#include <EGL/eglext.h> + +namespace egl +{ +struct Current +{ + EGLint error; + EGLenum API; + EGLDisplay display; + EGLSurface drawSurface; + EGLSurface readSurface; +}; + +void setCurrentError(EGLint error); +EGLint getCurrentError(); + +void setCurrentAPI(EGLenum API); +EGLenum getCurrentAPI(); + +void setCurrentDisplay(EGLDisplay dpy); +EGLDisplay getCurrentDisplay(); + +void setCurrentDrawSurface(EGLSurface surface); +EGLSurface getCurrentDrawSurface(); + +void setCurrentReadSurface(EGLSurface surface); +EGLSurface getCurrentReadSurface(); +} + +void error(EGLint errorCode); + +template<class T> +const T &error(EGLint errorCode, const T &returnValue) +{ + error(errorCode); + + return returnValue; +} + +template<class T> +const T &success(const T &returnValue) +{ + egl::setCurrentError(EGL_SUCCESS); + + return returnValue; +} + +#endif // LIBEGL_MAIN_H_ diff --git a/src/3rdparty/angle/src/libEGL/resource.h b/src/3rdparty/angle/src/libEGL/resource.h new file mode 100644 index 0000000000..3921f4c077 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by libEGL.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif |