Commit 063d9e78 by Austin Kinross Committed by Jamie Madill

Add support for EGL_EXT_platform_device

This allows an application to use EGLDeviceEXT to initialize EGL. For example, if an application wants to initialize EGL using an existing D3D11 device (instead of ANGLE creating its D3D device), then the app may create an EGLDeviceEXT using EGL_ANGLE_device_creation_d3d11, and use this device to initialize EGL via EGL_EXT_platform_device. BUG=angleproject:1190 Change-Id: Ife91ce95a63e29eb2b3f05aedfb668e4cac8f5ce Reviewed-on: https://chromium-review.googlesource.com/313444Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Tested-by: 's avatarAustin Kinross <aukinros@microsoft.com>
parent fc1a44a1
......@@ -648,6 +648,7 @@ std::vector<std::string> DeviceExtensions::getStrings() const
ClientExtensions::ClientExtensions()
: clientExtensions(false),
platformBase(false),
platformDevice(false),
platformANGLE(false),
platformANGLED3D(false),
platformANGLEOpenGL(false),
......@@ -666,6 +667,7 @@ std::vector<std::string> ClientExtensions::getStrings() const
// | Extension name | Supported flag | Output vector |
InsertExtensionString("EGL_EXT_client_extensions", clientExtensions, &extensionStrings);
InsertExtensionString("EGL_EXT_platform_base", platformBase, &extensionStrings);
InsertExtensionString("EGL_EXT_platform_device", platformDevice, &extensionStrings);
InsertExtensionString("EGL_ANGLE_platform_angle", platformANGLE, &extensionStrings);
InsertExtensionString("EGL_ANGLE_platform_angle_d3d", platformANGLED3D, &extensionStrings);
InsertExtensionString("EGL_ANGLE_platform_angle_opengl", platformANGLEOpenGL, &extensionStrings);
......
......@@ -471,6 +471,9 @@ struct ClientExtensions
// EGL_EXT_platform_base
bool platformBase;
// EGL_EXT_platform_device
bool platformDevice;
// EGL_ANGLE_platform_angle
bool platformANGLE;
......
......@@ -85,14 +85,52 @@ static WindowSurfaceMap *GetWindowSurfaces()
return &windowSurfaces;
}
typedef std::map<EGLNativeDisplayType, Display*> DisplayMap;
static DisplayMap *GetDisplayMap()
typedef std::map<EGLNativeDisplayType, Display *> ANGLEPlatformDisplayMap;
static ANGLEPlatformDisplayMap *GetANGLEPlatformDisplayMap()
{
static DisplayMap displays;
static ANGLEPlatformDisplayMap displays;
return &displays;
}
rx::DisplayImpl *CreateDisplayImpl(const AttributeMap &attribMap)
typedef std::map<Device *, Display *> DevicePlatformDisplayMap;
static DevicePlatformDisplayMap *GetDevicePlatformDisplayMap()
{
static DevicePlatformDisplayMap displays;
return &displays;
}
rx::DisplayImpl *CreateDisplayFromDevice(Device *eglDevice)
{
rx::DisplayImpl *impl = nullptr;
switch (eglDevice->getType())
{
#if defined(ANGLE_ENABLE_D3D11)
case EGL_D3D11_DEVICE_ANGLE:
impl = new rx::DisplayD3D();
break;
#endif
#if defined(ANGLE_ENABLE_D3D9)
case EGL_D3D9_DEVICE_ANGLE:
// Currently the only way to get EGLDeviceEXT representing a D3D9 device
// is to retrieve one from an already-existing EGLDisplay.
// When eglGetPlatformDisplayEXT is called with a D3D9 EGLDeviceEXT,
// the already-existing display should be returned.
// Therefore this codepath to create a new display from the device
// should never be hit.
UNREACHABLE();
break;
#endif
default:
UNREACHABLE();
break;
}
ASSERT(impl != nullptr);
return impl;
}
rx::DisplayImpl *CreateDisplayFromAttribs(const AttributeMap &attribMap)
{
rx::DisplayImpl *impl = nullptr;
EGLint displayType = attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
......@@ -149,15 +187,17 @@ rx::DisplayImpl *CreateDisplayImpl(const AttributeMap &attribMap)
}
Display *Display::getDisplay(EGLNativeDisplayType displayId, const AttributeMap &attribMap)
Display *Display::GetDisplayFromAttribs(void *native_display, const AttributeMap &attribMap)
{
// Initialize the global platform if not already
InitDefaultPlatformImpl();
Display *display = NULL;
Display *display = nullptr;
EGLNativeDisplayType displayId = static_cast<EGLNativeDisplayType>(native_display);
DisplayMap *displays = GetDisplayMap();
DisplayMap::const_iterator iter = displays->find(displayId);
ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
ANGLEPlatformDisplayMap::const_iterator iter = displays->find(displayId);
if (iter != displays->end())
{
display = iter->second;
......@@ -171,21 +211,71 @@ Display *Display::getDisplay(EGLNativeDisplayType displayId, const AttributeMap
return NULL;
}
display = new Display(displayId);
display = new Display(EGL_PLATFORM_ANGLE_ANGLE, displayId, nullptr);
displays->insert(std::make_pair(displayId, display));
}
// Apply new attributes if the display is not initialized yet.
if (!display->isInitialized())
{
rx::DisplayImpl* impl = CreateDisplayImpl(attribMap);
rx::DisplayImpl *impl = CreateDisplayFromAttribs(attribMap);
display->setAttributes(impl, attribMap);
}
return display;
}
Display::Display(EGLNativeDisplayType displayId)
Display *Display::GetDisplayFromDevice(void *native_display)
{
// Initialize the global platform if not already
InitDefaultPlatformImpl();
Display *display = nullptr;
Device *eglDevice = reinterpret_cast<Device *>(native_display);
ASSERT(Device::IsValidDevice(eglDevice));
ANGLEPlatformDisplayMap *anglePlatformDisplays = GetANGLEPlatformDisplayMap();
DevicePlatformDisplayMap *devicePlatformDisplays = GetDevicePlatformDisplayMap();
// First see if this eglDevice is in use by a Display created using ANGLE platform
for (auto &displayMapEntry : *anglePlatformDisplays)
{
egl::Display *iterDisplay = displayMapEntry.second;
if (iterDisplay->getDevice() == eglDevice)
{
display = iterDisplay;
}
}
if (display == nullptr)
{
// See if the eglDevice is in use by a Display created using the DEVICE platform
DevicePlatformDisplayMap::const_iterator iter = devicePlatformDisplays->find(eglDevice);
if (iter != devicePlatformDisplays->end())
{
display = iter->second;
}
}
if (display == nullptr)
{
// Otherwise create a new Display
display = new Display(EGL_PLATFORM_DEVICE_EXT, 0, eglDevice);
devicePlatformDisplays->insert(std::make_pair(eglDevice, display));
}
// Apply new attributes if the display is not initialized yet.
if (!display->isInitialized())
{
rx::DisplayImpl *impl = CreateDisplayFromDevice(eglDevice);
display->setAttributes(impl, egl::AttributeMap());
}
return display;
}
Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice)
: mImplementation(nullptr),
mDisplayId(displayId),
mAttributeMap(),
......@@ -196,7 +286,8 @@ Display::Display(EGLNativeDisplayType displayId)
mDisplayExtensions(),
mDisplayExtensionString(),
mVendorString(),
mDevice(nullptr)
mDevice(eglDevice),
mPlatform(platform)
{
}
......@@ -204,11 +295,27 @@ Display::~Display()
{
terminate();
DisplayMap *displays = GetDisplayMap();
DisplayMap::iterator iter = displays->find(mDisplayId);
if (iter != displays->end())
if (mPlatform == EGL_PLATFORM_ANGLE_ANGLE)
{
ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
ANGLEPlatformDisplayMap::iterator iter = displays->find(mDisplayId);
if (iter != displays->end())
{
displays->erase(iter);
}
}
else if (mPlatform == EGL_PLATFORM_DEVICE_EXT)
{
DevicePlatformDisplayMap *displays = GetDevicePlatformDisplayMap();
DevicePlatformDisplayMap::iterator iter = displays->find(mDevice);
if (iter != displays->end())
{
displays->erase(iter);
}
}
else
{
displays->erase(iter);
UNREACHABLE();
}
SafeDelete(mDevice);
......@@ -264,24 +371,34 @@ Error Display::initialize()
initDisplayExtensions();
initVendorString();
if (mDisplayExtensions.deviceQuery)
// Populate the Display's EGLDeviceEXT if the Display wasn't created using one
if (mPlatform != EGL_PLATFORM_DEVICE_EXT)
{
rx::DeviceImpl *impl = nullptr;
error = mImplementation->getDevice(&impl);
if (error.isError())
if (mDisplayExtensions.deviceQuery)
{
return error;
}
rx::DeviceImpl *impl = nullptr;
error = mImplementation->getDevice(&impl);
if (error.isError())
{
return error;
}
error = Device::CreateDevice(this, impl, &mDevice);
if (error.isError())
error = Device::CreateDevice(this, impl, &mDevice);
if (error.isError())
{
return error;
}
}
else
{
return error;
mDevice = nullptr;
}
}
else
{
mDevice = nullptr;
// For EGL_PLATFORM_DEVICE_EXT, mDevice should always be populated using
// an external device
ASSERT(mDevice != nullptr);
}
mInitialized = true;
......@@ -305,7 +422,12 @@ void Display::terminate()
mConfigSet.clear();
SafeDelete(mDevice);
if (mDevice != nullptr && mDevice->getOwningDisplay() != nullptr)
{
// Don't delete the device if it was created externally using eglCreateDeviceANGLE
// We also shouldn't set it to null in case eglInitialize() is called again later
SafeDelete(mDevice);
}
mImplementation->terminate();
......@@ -712,6 +834,7 @@ static ClientExtensions GenerateClientExtensions()
#if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
extensions.platformANGLED3D = true;
extensions.platformDevice = true;
#endif
#if defined(ANGLE_ENABLE_OPENGL)
......@@ -771,8 +894,17 @@ bool Display::isValidNativeWindow(EGLNativeWindowType window) const
bool Display::isValidDisplay(const egl::Display *display)
{
const DisplayMap *displayMap = GetDisplayMap();
for (const auto &displayPair : *displayMap)
const ANGLEPlatformDisplayMap *anglePlatformDisplayMap = GetANGLEPlatformDisplayMap();
for (const auto &displayPair : *anglePlatformDisplayMap)
{
if (displayPair.second == display)
{
return true;
}
}
const DevicePlatformDisplayMap *devicePlatformDisplayMap = GetDevicePlatformDisplayMap();
for (const auto &displayPair : *devicePlatformDisplayMap)
{
if (displayPair.second == display)
{
......
......@@ -44,7 +44,8 @@ class Display final : angle::NonCopyable
Error initialize();
void terminate();
static egl::Display *getDisplay(EGLNativeDisplayType displayId, const AttributeMap &attribMap);
static egl::Display *GetDisplayFromDevice(void *native_display);
static egl::Display *GetDisplayFromAttribs(void *native_display, const AttributeMap &attribMap);
static const ClientExtensions &getClientExtensions();
static const std::string &getClientExtensionString();
......@@ -101,9 +102,10 @@ class Display final : angle::NonCopyable
rx::DisplayImpl *getImplementation() { return mImplementation; }
Device *getDevice() const;
EGLenum getPlatform() const { return mPlatform; }
private:
Display(EGLNativeDisplayType displayId);
Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice);
void setAttributes(rx::DisplayImpl *impl, const AttributeMap &attribMap);
......@@ -135,6 +137,7 @@ class Display final : angle::NonCopyable
std::string mVendorString;
Device *mDevice;
EGLenum mPlatform;
};
}
......
......@@ -55,10 +55,13 @@ egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer)
std::vector<CreateRendererD3DFunction> rendererCreationFunctions;
const auto &attribMap = display->getAttributeMap();
EGLNativeDisplayType nativeDisplay = display->getNativeDisplayId();
if (display->getPlatform() == EGL_PLATFORM_ANGLE_ANGLE)
{
const auto &attribMap = display->getAttributeMap();
EGLNativeDisplayType nativeDisplay = display->getNativeDisplayId();
EGLint requestedDisplayType = attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
EGLint requestedDisplayType =
attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
# if defined(ANGLE_ENABLE_D3D11)
if (nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ||
......@@ -77,27 +80,41 @@ egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer)
}
# endif
if (nativeDisplay != EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE &&
nativeDisplay != EGL_D3D11_ONLY_DISPLAY_ANGLE &&
requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)
{
if (nativeDisplay != EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE &&
nativeDisplay != EGL_D3D11_ONLY_DISPLAY_ANGLE &&
requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)
{
// The default display is requested, try the D3D9 and D3D11 renderers, order them using
// the definition of ANGLE_DEFAULT_D3D11
# if ANGLE_DEFAULT_D3D11
# if defined(ANGLE_ENABLE_D3D11)
rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
# endif
# if defined(ANGLE_ENABLE_D3D9)
rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer9>);
rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer9>);
# endif
# else
# if defined(ANGLE_ENABLE_D3D9)
rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer9>);
rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer9>);
# endif
# if defined(ANGLE_ENABLE_D3D11)
rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
# endif
# endif
}
}
else if (display->getPlatform() == EGL_PLATFORM_DEVICE_EXT)
{
#if defined(ANGLE_ENABLE_D3D11)
if (display->getDevice()->getType() == EGL_D3D11_DEVICE_ANGLE)
{
rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
}
#endif
}
else
{
UNIMPLEMENTED();
}
egl::Error result(EGL_NOT_INITIALIZED, "No available renderers.");
......
......@@ -45,8 +45,7 @@ RendererD3D::RendererD3D(egl::Display *display)
mDeviceLost(false),
mAnnotator(nullptr),
mScratchMemoryBufferResetCounter(0),
mWorkaroundsInitialized(false),
mEGLDevice(nullptr)
mWorkaroundsInitialized(false)
{
}
......@@ -57,8 +56,6 @@ RendererD3D::~RendererD3D()
void RendererD3D::cleanup()
{
SafeDelete(mEGLDevice);
mScratchMemoryBuffer.resize(0);
for (auto &incompleteTexture : mIncompleteTextures)
{
......@@ -736,20 +733,4 @@ gl::DebugAnnotator *RendererD3D::getAnnotator()
ASSERT(mAnnotator);
return mAnnotator;
}
egl::Error RendererD3D::getEGLDevice(DeviceImpl **device)
{
if (mEGLDevice == nullptr)
{
egl::Error error = createEGLDevice(&mEGLDevice);
if (error.isError())
{
return error;
}
}
*device = static_cast<DeviceImpl *>(mEGLDevice);
return egl::Error(EGL_SUCCESS);
}
}
......@@ -254,7 +254,7 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
// In D3D11, faster than calling setTexture a jillion times
virtual gl::Error clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd) = 0;
egl::Error getEGLDevice(DeviceImpl **device);
virtual egl::Error getEGLDevice(DeviceImpl **device) = 0;
protected:
virtual bool getLUID(LUID *adapterLuid) const = 0;
......@@ -264,8 +264,6 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
virtual void createAnnotator() = 0;
virtual egl::Error createEGLDevice(DeviceD3D **outDevice) = 0;
// dirtyPointer is a special value that will make the comparison with any valid pointer fail and force the renderer to re-apply the state.
static const uintptr_t DirtyPointer;
......@@ -333,8 +331,6 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
mutable bool mWorkaroundsInitialized;
mutable WorkaroundsD3D mWorkarounds;
DeviceD3D *mEGLDevice;
};
struct dx_VertexConstants
......
......@@ -499,6 +499,8 @@ Renderer11::Renderer11(egl::Display *display)
mD3d11Module = NULL;
mDxgiModule = NULL;
mCreatedWithDeviceEXT = false;
mEGLDevice = nullptr;
mDevice = NULL;
mDeviceContext = NULL;
......@@ -517,58 +519,69 @@ Renderer11::Renderer11(egl::Display *display)
ZeroMemory(&mAdapterDescription, sizeof(mAdapterDescription));
const auto &attributes = mDisplay->getAttributeMap();
if (mDisplay->getPlatform() == EGL_PLATFORM_ANGLE_ANGLE)
{
const auto &attributes = mDisplay->getAttributeMap();
EGLint requestedMajorVersion = attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE);
EGLint requestedMinorVersion = attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE);
EGLint requestedMajorVersion =
attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE);
EGLint requestedMinorVersion =
attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE);
if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 11)
{
if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0)
if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 11)
{
mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_11_0);
if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0)
{
mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_11_0);
}
}
}
if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 10)
{
if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1)
if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 10)
{
mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_1);
if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1)
{
mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_1);
}
if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0)
{
mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_0);
}
}
if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0)
if (requestedMajorVersion == 9 && requestedMinorVersion == 3)
{
mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_0);
mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_3);
}
}
if (requestedMajorVersion == 9 && requestedMinorVersion == 3)
{
mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_3);
}
EGLint requestedDeviceType = attributes.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,
EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
switch (requestedDeviceType)
{
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE:
mDriverType = D3D_DRIVER_TYPE_HARDWARE;
break;
EGLint requestedDeviceType = attributes.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,
EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
switch (requestedDeviceType)
{
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE:
mDriverType = D3D_DRIVER_TYPE_HARDWARE;
break;
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE:
mDriverType = D3D_DRIVER_TYPE_WARP;
break;
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE:
mDriverType = D3D_DRIVER_TYPE_WARP;
break;
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE:
mDriverType = D3D_DRIVER_TYPE_REFERENCE;
break;
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE:
mDriverType = D3D_DRIVER_TYPE_REFERENCE;
break;
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE:
mDriverType = D3D_DRIVER_TYPE_NULL;
break;
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE:
mDriverType = D3D_DRIVER_TYPE_NULL;
break;
default:
UNREACHABLE();
default:
UNREACHABLE();
}
}
else if (display->getPlatform() == EGL_PLATFORM_DEVICE_EXT)
{
mEGLDevice = GetImplAs<DeviceD3D>(display->getDevice());
ASSERT(mEGLDevice != nullptr);
mCreatedWithDeviceEXT = true;
}
initializeDebugAnnotator();
......@@ -585,68 +598,12 @@ Renderer11::~Renderer11()
egl::Error Renderer11::initialize()
{
#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = nullptr;
{
SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.Renderer11InitializeDLLsMS");
TRACE_EVENT0("gpu.angle", "Renderer11::initialize (Load DLLs)");
mDxgiModule = LoadLibrary(TEXT("dxgi.dll"));
mD3d11Module = LoadLibrary(TEXT("d3d11.dll"));
if (mD3d11Module == nullptr || mDxgiModule == nullptr)
{
return egl::Error(EGL_NOT_INITIALIZED,
D3D11_INIT_MISSING_DEP,
"Could not load D3D11 or DXGI library.");
}
// create the D3D11 device
ASSERT(mDevice == nullptr);
D3D11CreateDevice = reinterpret_cast<PFN_D3D11_CREATE_DEVICE>(GetProcAddress(mD3d11Module, "D3D11CreateDevice"));
if (D3D11CreateDevice == nullptr)
{
return egl::Error(EGL_NOT_INITIALIZED,
D3D11_INIT_MISSING_DEP,
"Could not retrieve D3D11CreateDevice address.");
}
}
#endif
HRESULT result = S_OK;
#ifdef _DEBUG
{
TRACE_EVENT0("gpu.angle", "D3D11CreateDevice (Debug)");
result = D3D11CreateDevice(
NULL, mDriverType, NULL, D3D11_CREATE_DEVICE_DEBUG, mAvailableFeatureLevels.data(),
static_cast<unsigned int>(mAvailableFeatureLevels.size()), D3D11_SDK_VERSION, &mDevice,
&(mRenderer11DeviceCaps.featureLevel), &mDeviceContext);
}
if (!mDevice || FAILED(result))
{
ERR("Failed creating Debug D3D11 device - falling back to release runtime.\n");
}
if (!mDevice || FAILED(result))
#endif
egl::Error error = initializeD3DDevice();
if (error.isError())
{
SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.D3D11CreateDeviceMS");
TRACE_EVENT0("gpu.angle", "D3D11CreateDevice");
result = D3D11CreateDevice(NULL, mDriverType, NULL, 0, mAvailableFeatureLevels.data(),
static_cast<unsigned int>(mAvailableFeatureLevels.size()),
D3D11_SDK_VERSION, &mDevice,
&(mRenderer11DeviceCaps.featureLevel), &mDeviceContext);
// Cleanup done by destructor
if (!mDevice || FAILED(result))
{
ANGLE_HISTOGRAM_SPARSE_SLOWLY("GPU.ANGLE.D3D11CreateDeviceError", static_cast<int>(result));
return egl::Error(EGL_NOT_INITIALIZED,
D3D11_INIT_CREATEDEVICE_ERROR,
"Could not create D3D11 device.");
}
return error;
}
#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
......@@ -795,6 +752,106 @@ egl::Error Renderer11::initialize()
return egl::Error(EGL_SUCCESS);
}
egl::Error Renderer11::initializeD3DDevice()
{
HRESULT result = S_OK;
if (!mCreatedWithDeviceEXT)
{
#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = nullptr;
{
SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.Renderer11InitializeDLLsMS");
TRACE_EVENT0("gpu.angle", "Renderer11::initialize (Load DLLs)");
mDxgiModule = LoadLibrary(TEXT("dxgi.dll"));
mD3d11Module = LoadLibrary(TEXT("d3d11.dll"));
if (mD3d11Module == nullptr || mDxgiModule == nullptr)
{
return egl::Error(EGL_NOT_INITIALIZED, D3D11_INIT_MISSING_DEP,
"Could not load D3D11 or DXGI library.");
}
// create the D3D11 device
ASSERT(mDevice == nullptr);
D3D11CreateDevice = reinterpret_cast<PFN_D3D11_CREATE_DEVICE>(
GetProcAddress(mD3d11Module, "D3D11CreateDevice"));
if (D3D11CreateDevice == nullptr)
{
return egl::Error(EGL_NOT_INITIALIZED, D3D11_INIT_MISSING_DEP,
"Could not retrieve D3D11CreateDevice address.");
}
}
#endif
#ifdef _DEBUG
{
TRACE_EVENT0("gpu.angle", "D3D11CreateDevice (Debug)");
result = D3D11CreateDevice(
NULL, mDriverType, NULL, D3D11_CREATE_DEVICE_DEBUG, mAvailableFeatureLevels.data(),
static_cast<unsigned int>(mAvailableFeatureLevels.size()), D3D11_SDK_VERSION,
&mDevice, &(mRenderer11DeviceCaps.featureLevel), &mDeviceContext);
}
if (!mDevice || FAILED(result))
{
ERR("Failed creating Debug D3D11 device - falling back to release runtime.\n");
}
if (!mDevice || FAILED(result))
#endif
{
SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.D3D11CreateDeviceMS");
TRACE_EVENT0("gpu.angle", "D3D11CreateDevice");
result = D3D11CreateDevice(NULL, mDriverType, NULL, 0, mAvailableFeatureLevels.data(),
static_cast<unsigned int>(mAvailableFeatureLevels.size()),
D3D11_SDK_VERSION, &mDevice,
&(mRenderer11DeviceCaps.featureLevel), &mDeviceContext);
// Cleanup done by destructor
if (!mDevice || FAILED(result))
{
ANGLE_HISTOGRAM_SPARSE_SLOWLY("GPU.ANGLE.D3D11CreateDeviceError",
static_cast<int>(result));
return egl::Error(EGL_NOT_INITIALIZED, D3D11_INIT_CREATEDEVICE_ERROR,
"Could not create D3D11 device.");
}
}
}
else
{
// We should use the inputted D3D11 device instead
void *device = nullptr;
egl::Error error = mEGLDevice->getDevice(&device);
if (error.isError())
{
return error;
}
ID3D11Device *d3dDevice = reinterpret_cast<ID3D11Device *>(device);
if (FAILED(d3dDevice->GetDeviceRemovedReason()))
{
return egl::Error(EGL_NOT_INITIALIZED, "Inputted D3D11 device has been lost.");
}
if (d3dDevice->GetFeatureLevel() < D3D_FEATURE_LEVEL_9_3)
{
return egl::Error(EGL_NOT_INITIALIZED,
"Inputted D3D11 device must be Feature Level 9_3 or greater.");
}
// The Renderer11 adds a ref to the inputted D3D11 device, like D3D11CreateDevice does.
mDevice = d3dDevice;
mDevice->AddRef();
mDevice->GetImmediateContext(&mDeviceContext);
mRenderer11DeviceCaps.featureLevel = mDevice->GetFeatureLevel();
}
return egl::Error(EGL_SUCCESS);
}
// 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.
......@@ -2597,6 +2654,13 @@ void Renderer11::release()
releaseDeviceResources();
if (!mCreatedWithDeviceEXT)
{
// Only delete the device if the Renderer11 owns it
// Otherwise we should keep it around in case we try to reinitialize the renderer later
SafeDelete(mEGLDevice);
}
SafeRelease(mDxgiFactory);
SafeRelease(mDxgiAdapter);
......@@ -4086,20 +4150,23 @@ gl::Error Renderer11::clearTextures(gl::SamplerType samplerType, size_t rangeSta
return gl::Error(GL_NO_ERROR);
}
egl::Error Renderer11::createEGLDevice(DeviceD3D **outDevice)
egl::Error Renderer11::getEGLDevice(DeviceImpl **device)
{
ASSERT(mDevice != nullptr);
DeviceD3D *device = new DeviceD3D();
egl::Error error =
device->initialize(reinterpret_cast<void *>(mDevice), EGL_D3D11_DEVICE_ANGLE, EGL_FALSE);
if (error.isError())
if (mEGLDevice == nullptr)
{
SafeDelete(device);
return error;
ASSERT(mDevice != nullptr);
mEGLDevice = new DeviceD3D();
egl::Error error = mEGLDevice->initialize(reinterpret_cast<void *>(mDevice),
EGL_D3D11_DEVICE_ANGLE, EGL_FALSE);
if (error.isError())
{
SafeDelete(mEGLDevice);
return error;
}
}
*outDevice = device;
*device = static_cast<DeviceImpl *>(mEGLDevice);
return egl::Error(EGL_SUCCESS);
}
}
......@@ -283,13 +283,13 @@ class Renderer11 : public RendererD3D
void onSwap();
void onBufferDelete(const Buffer11 *deleted);
egl::Error getEGLDevice(DeviceImpl **device) override;
protected:
void createAnnotator() override;
gl::Error clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd) override;
gl::Error applyShadersImpl(const gl::Data &data, GLenum drawMode) override;
egl::Error createEGLDevice(DeviceD3D **outDevice) override;
void syncState(const gl::State &state, const gl::State::DirtyBits &bitmask) override;
private:
......@@ -335,9 +335,12 @@ class Renderer11 : public RendererD3D
HMODULE mDxgiModule;
std::vector<D3D_FEATURE_LEVEL> mAvailableFeatureLevels;
D3D_DRIVER_TYPE mDriverType;
bool mCreatedWithDeviceEXT;
DeviceD3D *mEGLDevice;
HLSLCompiler mCompiler;
egl::Error initializeD3DDevice();
void initializeDevice();
void releaseDeviceResources();
void release();
......
......@@ -132,6 +132,8 @@ Renderer9::Renderer9(egl::Display *display)
mAppliedProgramSerial = 0;
initializeDebugAnnotator();
mEGLDevice = nullptr;
}
Renderer9::~Renderer9()
......@@ -154,6 +156,7 @@ void Renderer9::release()
releaseDeviceResources();
SafeDelete(mEGLDevice);
SafeRelease(mDevice);
SafeRelease(mDeviceEx);
SafeRelease(mD3d9);
......@@ -3061,20 +3064,23 @@ gl::Error Renderer9::clearTextures(gl::SamplerType samplerType, size_t rangeStar
return gl::Error(GL_NO_ERROR);
}
egl::Error Renderer9::createEGLDevice(DeviceD3D **outDevice)
egl::Error Renderer9::getEGLDevice(DeviceImpl **device)
{
ASSERT(mDevice != nullptr);
DeviceD3D *device = new DeviceD3D();
egl::Error error =
device->initialize(reinterpret_cast<void *>(mDevice), EGL_D3D9_DEVICE_ANGLE, EGL_FALSE);
if (error.isError())
if (mEGLDevice == nullptr)
{
SafeDelete(device);
return error;
ASSERT(mDevice != nullptr);
mEGLDevice = new DeviceD3D();
egl::Error error = mEGLDevice->initialize(reinterpret_cast<void *>(mDevice),
EGL_D3D9_DEVICE_ANGLE, EGL_FALSE);
if (error.isError())
{
SafeDelete(mEGLDevice);
return error;
}
}
*outDevice = device;
*device = static_cast<DeviceImpl *>(mEGLDevice);
return egl::Error(EGL_SUCCESS);
}
......
......@@ -251,13 +251,13 @@ class Renderer9 : public RendererD3D
D3DDEVTYPE getD3D9DeviceType() const { return mDeviceType; }
egl::Error getEGLDevice(DeviceImpl **device) override;
protected:
void createAnnotator() override;
gl::Error clearTextures(gl::SamplerType samplerType, size_t rangeStart, size_t rangeEnd) override;
gl::Error applyShadersImpl(const gl::Data &data, GLenum drawMode) override;
egl::Error createEGLDevice(DeviceD3D **outDevice) override;
private:
gl::Error drawArraysImpl(const gl::Data &data,
GLenum mode,
......@@ -415,6 +415,8 @@ class Renderer9 : public RendererD3D
gl::FramebufferAttachment *buffer;
} mNullColorbufferCache[NUM_NULL_COLORBUFFER_CACHE_ENTRIES];
UINT mMaxNullColorbufferLRU;
DeviceD3D *mEGLDevice;
};
}
......
......@@ -41,7 +41,7 @@ EGLDisplay EGLAPIENTRY GetDisplay(EGLNativeDisplayType display_id)
{
EVENT("(EGLNativeDisplayType display_id = 0x%0.8p)", display_id);
return Display::getDisplay(display_id, AttributeMap());
return Display::GetDisplayFromAttribs(reinterpret_cast<void *>(display_id), AttributeMap());
}
EGLBoolean EGLAPIENTRY Initialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
......
......@@ -143,144 +143,177 @@ EGLDisplay EGLAPIENTRY GetPlatformDisplayEXT(EGLenum platform, void *native_disp
return EGL_NO_DISPLAY;
}
break;
case EGL_PLATFORM_DEVICE_EXT:
if (!clientExtensions.platformDevice)
{
SetGlobalError(Error(EGL_BAD_PARAMETER, "Platform Device extension is not active"));
return EGL_NO_DISPLAY;
}
break;
default:
SetGlobalError(Error(EGL_BAD_CONFIG));
return EGL_NO_DISPLAY;
}
EGLint platformType = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
EGLint deviceType = EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE;
bool majorVersionSpecified = false;
bool minorVersionSpecified = false;
bool enableAutoTrimSpecified = false;
bool deviceTypeSpecified = false;
if (attrib_list)
if (platform == EGL_PLATFORM_ANGLE_ANGLE)
{
for (const EGLint *curAttrib = attrib_list; curAttrib[0] != EGL_NONE; curAttrib += 2)
EGLint platformType = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
EGLint deviceType = EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE;
bool majorVersionSpecified = false;
bool minorVersionSpecified = false;
bool enableAutoTrimSpecified = false;
bool deviceTypeSpecified = false;
if (attrib_list)
{
switch (curAttrib[0])
for (const EGLint *curAttrib = attrib_list; curAttrib[0] != EGL_NONE; curAttrib += 2)
{
case EGL_PLATFORM_ANGLE_TYPE_ANGLE:
switch (curAttrib[1])
switch (curAttrib[0])
{
case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
break;
case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
if (!clientExtensions.platformANGLED3D)
case EGL_PLATFORM_ANGLE_TYPE_ANGLE:
switch (curAttrib[1])
{
case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
break;
case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
if (!clientExtensions.platformANGLED3D)
{
SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
return EGL_NO_DISPLAY;
}
break;
case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
if (!clientExtensions.platformANGLEOpenGL)
{
SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
return EGL_NO_DISPLAY;
}
break;
default:
SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
return EGL_NO_DISPLAY;
}
platformType = curAttrib[1];
break;
case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
if (!clientExtensions.platformANGLEOpenGL)
case EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE:
if (curAttrib[1] != EGL_DONT_CARE)
{
majorVersionSpecified = true;
}
break;
case EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE:
if (curAttrib[1] != EGL_DONT_CARE)
{
minorVersionSpecified = true;
}
break;
case EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE:
switch (curAttrib[1])
{
case EGL_TRUE:
case EGL_FALSE:
break;
default:
SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
return EGL_NO_DISPLAY;
}
enableAutoTrimSpecified = true;
break;
default:
SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
return EGL_NO_DISPLAY;
}
platformType = curAttrib[1];
break;
case EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE:
if (curAttrib[1] != EGL_DONT_CARE)
{
majorVersionSpecified = true;
}
break;
case EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE:
if (curAttrib[1] != EGL_DONT_CARE)
{
minorVersionSpecified = true;
}
break;
case EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE:
switch (curAttrib[1])
{
case EGL_TRUE:
case EGL_FALSE:
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE:
switch (curAttrib[1])
{
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE:
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE:
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE:
deviceTypeSpecified = true;
break;
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE:
// This is a hidden option, accepted by the OpenGL back-end.
break;
default:
SetGlobalError(Error(EGL_BAD_ATTRIBUTE,
"Invalid value for "
"EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE "
"attrib"));
return EGL_NO_DISPLAY;
}
deviceType = curAttrib[1];
break;
default:
SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
return EGL_NO_DISPLAY;
default:
break;
}
enableAutoTrimSpecified = true;
break;
}
}
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE:
switch (curAttrib[1])
{
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE:
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE:
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE:
deviceTypeSpecified = true;
break;
if (!majorVersionSpecified && minorVersionSpecified)
{
SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
return EGL_NO_DISPLAY;
}
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE:
// This is a hidden option, accepted by the OpenGL back-end.
break;
if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE &&
platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
{
SetGlobalError(
Error(EGL_BAD_ATTRIBUTE,
"EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE requires a device type of "
"EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."));
return EGL_NO_DISPLAY;
}
default:
SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
return EGL_NO_DISPLAY;
}
deviceType = curAttrib[1];
break;
if (enableAutoTrimSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
{
SetGlobalError(
Error(EGL_BAD_ATTRIBUTE,
"EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE requires a device type of "
"EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."));
return EGL_NO_DISPLAY;
}
default:
break;
}
if (deviceTypeSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE &&
platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
{
SetGlobalError(
Error(EGL_BAD_ATTRIBUTE,
"EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE requires a device type of "
"EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE or EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE."));
return EGL_NO_DISPLAY;
}
}
if (!majorVersionSpecified && minorVersionSpecified)
{
SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
return EGL_NO_DISPLAY;
SetGlobalError(Error(EGL_SUCCESS));
return Display::GetDisplayFromAttribs(native_display, AttributeMap(attrib_list));
}
if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE &&
platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
else if (platform == EGL_PLATFORM_DEVICE_EXT)
{
SetGlobalError(Error(EGL_BAD_ATTRIBUTE, "EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE requires a device type of "
"EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."));
return EGL_NO_DISPLAY;
}
Device *eglDevice = reinterpret_cast<Device *>(native_display);
if (eglDevice == nullptr || !Device::IsValidDevice(eglDevice))
{
SetGlobalError(Error(EGL_BAD_ATTRIBUTE,
"native_display should be a valid EGL device if platform equals "
"EGL_PLATFORM_DEVICE_EXT"));
return EGL_NO_DISPLAY;
}
if (enableAutoTrimSpecified &&
platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
{
SetGlobalError(Error(EGL_BAD_ATTRIBUTE, "EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE requires a device type of "
"EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."));
return EGL_NO_DISPLAY;
SetGlobalError(Error(EGL_SUCCESS));
return Display::GetDisplayFromDevice(native_display);
}
if (deviceTypeSpecified &&
platformType != EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE &&
platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
else
{
SetGlobalError(Error(EGL_BAD_ATTRIBUTE, "EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE requires a device type of "
"EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE or EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE."));
UNREACHABLE();
return EGL_NO_DISPLAY;
}
SetGlobalError(Error(EGL_SUCCESS));
EGLNativeDisplayType displayId = static_cast<EGLNativeDisplayType>(native_display);
return Display::getDisplay(displayId, AttributeMap(attrib_list));
}
// EGL_EXT_device_query
......
......@@ -12,8 +12,11 @@
#define ANGLE_ENABLE_D3D11
#endif
#include "test_utils/ANGLETest.h"
#include <d3d11.h>
#include "com_utils.h"
#include "OSWindow.h"
#include "test_utils/ANGLETest.h"
using namespace angle;
......@@ -26,7 +29,12 @@ class EGLDeviceCreationTest : public testing::Test
mD3D11CreateDevice(nullptr),
mDevice(nullptr),
mDeviceContext(nullptr),
mDeviceCreationD3D11ExtAvailable(false)
mDeviceCreationD3D11ExtAvailable(false),
mOSWindow(nullptr),
mDisplay(EGL_NO_DISPLAY),
mSurface(EGL_NO_SURFACE),
mContext(EGL_NO_CONTEXT),
mConfig(0)
{
}
......@@ -64,23 +72,105 @@ class EGLDeviceCreationTest : public testing::Test
{
SafeRelease(mDevice);
SafeRelease(mDeviceContext);
SafeDelete(mOSWindow);
if (mSurface != EGL_NO_SURFACE)
{
eglDestroySurface(mDisplay, mSurface);
mSurface = EGL_NO_SURFACE;
}
if (mContext != EGL_NO_CONTEXT)
{
eglDestroyContext(mDisplay, mContext);
mContext = EGL_NO_CONTEXT;
}
if (mDisplay != EGL_NO_DISPLAY)
{
eglTerminate(mDisplay);
mDisplay = EGL_NO_DISPLAY;
}
}
bool CreateD3D11Device()
void CreateD3D11Device()
{
ASSERT(mD3D11Available);
ASSERT_TRUE(mD3D11Available);
ASSERT_EQ(nullptr, mDevice); // The device shouldn't be created twice
HRESULT hr =
mD3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, 0, 0, nullptr, 0,
D3D11_SDK_VERSION, &mDevice, &mFeatureLevel, &mDeviceContext);
if (FAILED(hr) || mFeatureLevel < D3D_FEATURE_LEVEL_9_3)
{
std::cout << "Could not create D3D11 device, skipping test" << std::endl;
return false;
}
ASSERT_TRUE(SUCCEEDED(hr));
ASSERT_GE(mFeatureLevel, D3D_FEATURE_LEVEL_9_3);
}
void CreateD3D11FL9_3Device()
{
ASSERT_TRUE(mD3D11Available);
ASSERT_EQ(nullptr, mDevice);
D3D_FEATURE_LEVEL fl93 = D3D_FEATURE_LEVEL_9_3;
HRESULT hr =
mD3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, 0, 0, &fl93, 1, D3D11_SDK_VERSION,
&mDevice, &mFeatureLevel, &mDeviceContext);
ASSERT_TRUE(SUCCEEDED(hr));
}
void CreateWindowSurface()
{
EGLint majorVersion, minorVersion;
ASSERT_EQ(EGL_TRUE, eglInitialize(mDisplay, &majorVersion, &minorVersion));
eglBindAPI(EGL_OPENGL_ES_API);
ASSERT_EGL_SUCCESS();
return true;
// Choose a config
const EGLint configAttributes[] = {EGL_NONE};
EGLint configCount = 0;
ASSERT_EQ(EGL_TRUE, eglChooseConfig(mDisplay, configAttributes, &mConfig, 1, &configCount));
// Create an OS Window
mOSWindow = CreateOSWindow();
mOSWindow->initialize("EGLSurfaceTest", 64, 64);
// Create window surface
mSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), nullptr);
ASSERT_EGL_SUCCESS();
// Create EGL context
EGLint contextAttibutes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
mContext = eglCreateContext(mDisplay, mConfig, nullptr, contextAttibutes);
ASSERT_EGL_SUCCESS();
// Make the surface current
eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
ASSERT_EGL_SUCCESS();
}
// This triggers a D3D device lost on current Windows systems
// This behavior could potentially change in the future
void trigger9_3DeviceLost()
{
ID3D11Buffer *gsBuffer = nullptr;
D3D11_BUFFER_DESC bufferDesc = {0};
bufferDesc.ByteWidth = 64;
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
HRESULT result = mDevice->CreateBuffer(&bufferDesc, nullptr, &gsBuffer);
ASSERT_TRUE(SUCCEEDED(result));
mDeviceContext->GSSetConstantBuffers(0, 1, &gsBuffer);
SafeRelease(gsBuffer);
gsBuffer = nullptr;
result = mDevice->GetDeviceRemovedReason();
ASSERT_TRUE(FAILED(result));
}
bool mD3D11Available;
......@@ -92,18 +182,27 @@ class EGLDeviceCreationTest : public testing::Test
D3D_FEATURE_LEVEL mFeatureLevel;
bool mDeviceCreationD3D11ExtAvailable;
OSWindow *mOSWindow;
EGLDisplay mDisplay;
EGLSurface mSurface;
EGLContext mContext;
EGLConfig mConfig;
};
// Test that creating a EGLDeviceEXT from D3D11 device works, and it can be queried to retrieve
// D3D11 device
TEST_F(EGLDeviceCreationTest, BasicD3D11Device)
{
if (!mDeviceCreationD3D11ExtAvailable || !mD3D11Available || !CreateD3D11Device())
if (!mDeviceCreationD3D11ExtAvailable || !mD3D11Available)
{
std::cout << "EGLDevice creation and/or D3D11 not available, skipping test" << std::endl;
return;
}
CreateD3D11Device();
EGLDeviceEXT eglDevice =
eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDevice), nullptr);
ASSERT_NE(EGL_NO_DEVICE_EXT, eglDevice);
......@@ -123,12 +222,14 @@ TEST_F(EGLDeviceCreationTest, BasicD3D11Device)
// D3D11 device
TEST_F(EGLDeviceCreationTest, BasicD3D11DeviceViaFuncPointer)
{
if (!mDeviceCreationD3D11ExtAvailable || !mD3D11Available || !CreateD3D11Device())
if (!mDeviceCreationD3D11ExtAvailable || !mD3D11Available)
{
std::cout << "EGLDevice creation and/or D3D11 not available, skipping test" << std::endl;
return;
}
CreateD3D11Device();
PFNEGLCREATEDEVICEANGLEPROC createDeviceANGLE =
(PFNEGLCREATEDEVICEANGLEPROC)eglGetProcAddress("eglCreateDeviceANGLE");
PFNEGLRELEASEDEVICEANGLEPROC releaseDeviceANGLE =
......@@ -149,15 +250,147 @@ TEST_F(EGLDeviceCreationTest, BasicD3D11DeviceViaFuncPointer)
releaseDeviceANGLE(eglDevice);
}
// Test that creating a EGLDeviceEXT from D3D11 device works, and can be used for rendering
TEST_F(EGLDeviceCreationTest, RenderingUsingD3D11Device)
{
if (!mD3D11Available)
{
std::cout << "D3D11 not available, skipping test" << std::endl;
return;
}
CreateD3D11Device();
EGLDeviceEXT eglDevice =
eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDevice), nullptr);
ASSERT_EGL_SUCCESS();
// Create an EGLDisplay using the EGLDevice
mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevice, nullptr);
ASSERT_NE(EGL_NO_DISPLAY, mDisplay);
// Create a surface using the display
CreateWindowSurface();
// Perform some very basic rendering
glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_EQ(32, 32, 255, 0, 255, 255);
// Note that we must call TearDown() before we release the EGL device, since the display
// depends on the device
TearDown();
eglReleaseDeviceANGLE(eglDevice);
}
// Test that ANGLE doesn't try to recreate a D3D11 device if the inputted one is lost
TEST_F(EGLDeviceCreationTest, D3D11DeviceRecovery)
{
if (!mD3D11Available)
{
std::cout << "D3D11 not available, skipping test" << std::endl;
return;
}
// Force Feature Level 9_3 so we can easily trigger a device lost later
CreateD3D11FL9_3Device();
EGLDeviceEXT eglDevice =
eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDevice), nullptr);
ASSERT_EGL_SUCCESS();
// Create an EGLDisplay using the EGLDevice
mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevice, nullptr);
ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY);
// Create a surface using the display
CreateWindowSurface();
// Perform some very basic rendering
glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_EQ(32, 32, 255, 0, 255, 255);
ASSERT_GL_NO_ERROR();
// ANGLE's SwapChain11::initPassThroughResources doesn't handle device lost before
// eglSwapBuffers, so we must call eglSwapBuffers before we lose the device.
ASSERT_EQ(EGL_TRUE, eglSwapBuffers(mDisplay, mSurface));
// Trigger a lost device
trigger9_3DeviceLost();
// Destroy the old EGL Window Surface
if (mSurface != EGL_NO_SURFACE)
{
eglDestroySurface(mDisplay, mSurface);
mSurface = EGL_NO_SURFACE;
}
// Try to create a new window surface. In certain configurations this will recreate the D3D11
// device. We want to test that it doesn't recreate the D3D11 device when EGLDeviceEXT is
// used. The window surface creation should fail if a new D3D11 device isn't created.
mSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), nullptr);
ASSERT_EQ(EGL_NO_SURFACE, mSurface);
ASSERT_EGL_ERROR(EGL_BAD_ALLOC);
// Get the D3D11 device out of the EGLDisplay again. It should be the same one as above.
EGLAttrib device = 0;
EGLAttrib newEglDevice = 0;
ASSERT_EQ(EGL_TRUE, eglQueryDisplayAttribEXT(mDisplay, EGL_DEVICE_EXT, &newEglDevice));
ASSERT_EQ(EGL_TRUE, eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(newEglDevice),
EGL_D3D11_DEVICE_ANGLE, &device));
ID3D11Device *newDevice = reinterpret_cast<ID3D11Device *>(device);
ASSERT_EQ(reinterpret_cast<EGLDeviceEXT>(newEglDevice), eglDevice);
ASSERT_EQ(newDevice, mDevice);
// Note that we must call TearDown() before we release the EGL device, since the display
// depends on the device
TearDown();
eglReleaseDeviceANGLE(eglDevice);
}
// Test that calling eglGetPlatformDisplayEXT with the same device returns the same display
TEST_F(EGLDeviceCreationTest, getPlatformDisplayTwice)
{
if (!mD3D11Available)
{
std::cout << "D3D11 not available, skipping test" << std::endl;
return;
}
CreateD3D11Device();
EGLDeviceEXT eglDevice =
eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDevice), nullptr);
ASSERT_EGL_SUCCESS();
// Create an EGLDisplay using the EGLDevice
EGLDisplay display1 = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevice, nullptr);
ASSERT_NE(EGL_NO_DISPLAY, display1);
EGLDisplay display2 = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevice, nullptr);
ASSERT_NE(EGL_NO_DISPLAY, display2);
ASSERT_EQ(display1, display2);
eglTerminate(display1);
eglReleaseDeviceANGLE(eglDevice);
}
// Test that creating a EGLDeviceEXT from an invalid D3D11 device fails
TEST_F(EGLDeviceCreationTest, InvalidD3D11Device)
{
if (!mDeviceCreationD3D11ExtAvailable || !mD3D11Available || !CreateD3D11Device())
if (!mDeviceCreationD3D11ExtAvailable || !mD3D11Available)
{
std::cout << "EGLDevice creation and/or D3D11 not available, skipping test" << std::endl;
return;
}
CreateD3D11Device();
// Use mDeviceContext instead of mDevice
EGLDeviceEXT eglDevice = eglCreateDeviceANGLE(
EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDeviceContext), nullptr);
......@@ -168,12 +401,14 @@ TEST_F(EGLDeviceCreationTest, InvalidD3D11Device)
// Test that EGLDeviceEXT holds a ref to the D3D11 device
TEST_F(EGLDeviceCreationTest, D3D11DeviceReferenceCounting)
{
if (!mDeviceCreationD3D11ExtAvailable || !mD3D11Available || !CreateD3D11Device())
if (!mDeviceCreationD3D11ExtAvailable || !mD3D11Available)
{
std::cout << "EGLDevice creation and/or D3D11 not available, skipping test" << std::endl;
return;
}
CreateD3D11Device();
EGLDeviceEXT eglDevice =
eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDevice), nullptr);
ASSERT_NE(EGL_NO_DEVICE_EXT, eglDevice);
......@@ -331,6 +566,22 @@ TEST_P(EGLDeviceQueryTest, QueryDeviceBadAttribute)
}
}
// Ensure that:
// - calling getPlatformDisplayEXT using ANGLE_Platform with some parameters
// - extracting the EGLDeviceEXT from the EGLDisplay
// - calling getPlatformDisplayEXT with this EGLDeviceEXT
// results in the same EGLDisplay being returned from getPlatformDisplayEXT both times
TEST_P(EGLDeviceQueryTest, getPlatformDisplayDeviceReuse)
{
EGLAttrib eglDevice = 0;
EXPECT_EQ(EGL_TRUE,
eglQueryDisplayAttribEXT(getEGLWindow()->getDisplay(), EGL_DEVICE_EXT, &eglDevice));
EGLDisplay display2 = eglGetPlatformDisplayEXT(
EGL_PLATFORM_DEVICE_EXT, reinterpret_cast<EGLDeviceEXT>(eglDevice), nullptr);
EXPECT_EQ(getEGLWindow()->getDisplay(), display2);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST(EGLDeviceQueryTest, ES2_D3D9(), ES2_D3D11());
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment