Path: blob/main_old/src/tests/egl_tests/EGLDeviceTest.cpp
1693 views
//1// Copyright 2015 The ANGLE Project Authors. All rights reserved.2// Use of this source code is governed by a BSD-style license that can be3// found in the LICENSE file.4//56#ifndef ANGLE_ENABLE_D3D97# define ANGLE_ENABLE_D3D98#endif910#ifndef ANGLE_ENABLE_D3D1111# define ANGLE_ENABLE_D3D1112#endif1314#include <d3d11.h>1516#include "test_utils/ANGLETest.h"17#include "util/EGLWindow.h"18#include "util/OSWindow.h"19#include "util/com_utils.h"20#include "util/gles_loader_autogen.h"2122using namespace angle;2324class EGLDeviceCreationTest : public ANGLETest25{26protected:27EGLDeviceCreationTest()28: mD3D11Module(nullptr),29mD3D11CreateDevice(nullptr),30mDevice(nullptr),31mDeviceContext(nullptr),32mDeviceCreationD3D11ExtAvailable(false),33mOSWindow(nullptr),34mDisplay(EGL_NO_DISPLAY),35mSurface(EGL_NO_SURFACE),36mContext(EGL_NO_CONTEXT),37mConfig(0)38{}3940void testSetUp() override41{42ASSERT_TRUE(isD3D11Renderer());4344mD3D11Module = LoadLibrary(TEXT("d3d11.dll"));45if (mD3D11Module == nullptr)46{47std::cout << "Unable to LoadLibrary D3D11" << std::endl;48return;49}5051mD3D11CreateDevice = reinterpret_cast<PFN_D3D11_CREATE_DEVICE>(52GetProcAddress(mD3D11Module, "D3D11CreateDevice"));53if (mD3D11CreateDevice == nullptr)54{55std::cout << "Could not retrieve D3D11CreateDevice from d3d11.dll" << std::endl;56return;57}5859const char *extensionString =60static_cast<const char *>(eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS));61if (strstr(extensionString, "EGL_ANGLE_device_creation"))62{63if (strstr(extensionString, "EGL_ANGLE_device_creation_d3d11"))64{65mDeviceCreationD3D11ExtAvailable = true;66}67}68}6970void testTearDown() override71{72SafeRelease(mDevice);73SafeRelease(mDeviceContext);7475OSWindow::Delete(&mOSWindow);7677if (mSurface != EGL_NO_SURFACE)78{79eglDestroySurface(mDisplay, mSurface);80mSurface = EGL_NO_SURFACE;81}8283if (mContext != EGL_NO_CONTEXT)84{85eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);86eglDestroyContext(mDisplay, mContext);87mContext = EGL_NO_CONTEXT;88}8990if (mDisplay != EGL_NO_DISPLAY)91{92eglTerminate(mDisplay);93mDisplay = EGL_NO_DISPLAY;94}95}9697void CreateD3D11Device()98{99ASSERT_EQ(nullptr, mDevice); // The device shouldn't be created twice100101HRESULT hr =102mD3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, 0, 0, nullptr, 0,103D3D11_SDK_VERSION, &mDevice, &mFeatureLevel, &mDeviceContext);104105ASSERT_TRUE(SUCCEEDED(hr));106ASSERT_GE(mFeatureLevel, D3D_FEATURE_LEVEL_9_3);107}108109void CreateD3D11FL9_3Device()110{111ASSERT_EQ(nullptr, mDevice);112113D3D_FEATURE_LEVEL fl93 = D3D_FEATURE_LEVEL_9_3;114115HRESULT hr =116mD3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, 0, 0, &fl93, 1, D3D11_SDK_VERSION,117&mDevice, &mFeatureLevel, &mDeviceContext);118119ASSERT_TRUE(SUCCEEDED(hr));120}121122void CreateWindowSurface()123{124EGLint majorVersion, minorVersion;125ASSERT_EGL_TRUE(eglInitialize(mDisplay, &majorVersion, &minorVersion));126127eglBindAPI(EGL_OPENGL_ES_API);128ASSERT_EGL_SUCCESS();129130// Choose a config131const EGLint configAttributes[] = {EGL_NONE};132EGLint configCount = 0;133ASSERT_EGL_TRUE(eglChooseConfig(mDisplay, configAttributes, &mConfig, 1, &configCount));134135// Create an OS Window136mOSWindow = OSWindow::New();137mOSWindow->initialize("EGLSurfaceTest", 64, 64);138139// Create window surface140mSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), nullptr);141ASSERT_EGL_SUCCESS();142143// Create EGL context144EGLint contextAttibutes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};145mContext = eglCreateContext(mDisplay, mConfig, nullptr, contextAttibutes);146ASSERT_EGL_SUCCESS();147148// Make the surface current149eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);150ASSERT_EGL_SUCCESS();151}152153// This triggers a D3D device lost on current Windows systems154// This behavior could potentially change in the future155void trigger9_3DeviceLost()156{157ID3D11Buffer *gsBuffer = nullptr;158D3D11_BUFFER_DESC bufferDesc = {0};159bufferDesc.ByteWidth = 64;160bufferDesc.Usage = D3D11_USAGE_DEFAULT;161bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;162163HRESULT result = mDevice->CreateBuffer(&bufferDesc, nullptr, &gsBuffer);164ASSERT_TRUE(SUCCEEDED(result));165166mDeviceContext->GSSetConstantBuffers(0, 1, &gsBuffer);167SafeRelease(gsBuffer);168gsBuffer = nullptr;169170result = mDevice->GetDeviceRemovedReason();171ASSERT_TRUE(FAILED(result));172}173174HMODULE mD3D11Module;175PFN_D3D11_CREATE_DEVICE mD3D11CreateDevice;176177ID3D11Device *mDevice;178ID3D11DeviceContext *mDeviceContext;179D3D_FEATURE_LEVEL mFeatureLevel;180181bool mDeviceCreationD3D11ExtAvailable;182183OSWindow *mOSWindow;184185EGLDisplay mDisplay;186EGLSurface mSurface;187EGLContext mContext;188EGLConfig mConfig;189};190191// Test that creating a EGLDeviceEXT from D3D11 device works, and it can be queried to retrieve192// D3D11 device193TEST_P(EGLDeviceCreationTest, BasicD3D11Device)194{195ANGLE_SKIP_TEST_IF(!mDeviceCreationD3D11ExtAvailable);196197CreateD3D11Device();198199EGLDeviceEXT eglDevice =200eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDevice), nullptr);201ASSERT_NE(EGL_NO_DEVICE_EXT, eglDevice);202ASSERT_EGL_SUCCESS();203204EGLAttrib deviceAttrib;205eglQueryDeviceAttribEXT(eglDevice, EGL_D3D11_DEVICE_ANGLE, &deviceAttrib);206ASSERT_EGL_SUCCESS();207208ID3D11Device *queriedDevice = reinterpret_cast<ID3D11Device *>(deviceAttrib);209ASSERT_EQ(mFeatureLevel, queriedDevice->GetFeatureLevel());210211eglReleaseDeviceANGLE(eglDevice);212}213214// Test that creating a EGLDeviceEXT from D3D11 device works, and it can be queried to retrieve215// D3D11 device216TEST_P(EGLDeviceCreationTest, BasicD3D11DeviceViaFuncPointer)217{218ANGLE_SKIP_TEST_IF(!mDeviceCreationD3D11ExtAvailable);219220CreateD3D11Device();221222EGLDeviceEXT eglDevice =223eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDevice), nullptr);224ASSERT_NE(EGL_NO_DEVICE_EXT, eglDevice);225ASSERT_EGL_SUCCESS();226227EGLAttrib deviceAttrib;228eglQueryDeviceAttribEXT(eglDevice, EGL_D3D11_DEVICE_ANGLE, &deviceAttrib);229ASSERT_EGL_SUCCESS();230231ID3D11Device *queriedDevice = reinterpret_cast<ID3D11Device *>(deviceAttrib);232ASSERT_EQ(mFeatureLevel, queriedDevice->GetFeatureLevel());233234eglReleaseDeviceANGLE(eglDevice);235}236237// Test that creating a EGLDeviceEXT from D3D11 device works, and can be used for rendering238TEST_P(EGLDeviceCreationTest, RenderingUsingD3D11Device)239{240CreateD3D11Device();241242EGLDeviceEXT eglDevice =243eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDevice), nullptr);244ASSERT_EGL_SUCCESS();245246// Create an EGLDisplay using the EGLDevice247mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevice, nullptr);248ASSERT_NE(EGL_NO_DISPLAY, mDisplay);249250// Create a surface using the display251CreateWindowSurface();252253// Perform some very basic rendering254glClearColor(1.0f, 0.0f, 1.0f, 1.0f);255glClear(GL_COLOR_BUFFER_BIT);256EXPECT_PIXEL_EQ(32, 32, 255, 0, 255, 255);257258// Note that we must call TearDown() before we release the EGL device, since the display259// depends on the device260ASSERT_EGL_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));261testTearDown();262263eglReleaseDeviceANGLE(eglDevice);264}265266// Test that ANGLE doesn't try to recreate a D3D11 device if the inputted one is lost267TEST_P(EGLDeviceCreationTest, D3D11DeviceRecovery)268{269// Force Feature Level 9_3 so we can easily trigger a device lost later270CreateD3D11FL9_3Device();271272EGLDeviceEXT eglDevice =273eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDevice), nullptr);274ASSERT_EGL_SUCCESS();275276// Create an EGLDisplay using the EGLDevice277mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevice, nullptr);278ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY);279280// Create a surface using the display281CreateWindowSurface();282283// Perform some very basic rendering284glClearColor(1.0f, 0.0f, 1.0f, 1.0f);285glClear(GL_COLOR_BUFFER_BIT);286EXPECT_PIXEL_EQ(32, 32, 255, 0, 255, 255);287ASSERT_GL_NO_ERROR();288289// ANGLE's SwapChain11::initPassThroughResources doesn't handle device lost before290// eglSwapBuffers, so we must call eglSwapBuffers before we lose the device.291ASSERT_EGL_TRUE(eglSwapBuffers(mDisplay, mSurface));292293// Trigger a lost device294trigger9_3DeviceLost();295296// Destroy the old EGL Window Surface297if (mSurface != EGL_NO_SURFACE)298{299eglDestroySurface(mDisplay, mSurface);300mSurface = EGL_NO_SURFACE;301}302303// Try to create a new window surface. In certain configurations this will recreate the D3D11304// device. We want to test that it doesn't recreate the D3D11 device when EGLDeviceEXT is305// used. The window surface creation should fail if a new D3D11 device isn't created.306mSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), nullptr);307ASSERT_EQ(EGL_NO_SURFACE, mSurface);308ASSERT_EGL_ERROR(EGL_BAD_ALLOC);309310// Get the D3D11 device out of the EGLDisplay again. It should be the same one as above.311EGLAttrib device = 0;312EGLAttrib newEglDevice = 0;313ASSERT_EGL_TRUE(eglQueryDisplayAttribEXT(mDisplay, EGL_DEVICE_EXT, &newEglDevice));314ASSERT_EGL_TRUE(eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(newEglDevice),315EGL_D3D11_DEVICE_ANGLE, &device));316ID3D11Device *newDevice = reinterpret_cast<ID3D11Device *>(device);317318ASSERT_EQ(reinterpret_cast<EGLDeviceEXT>(newEglDevice), eglDevice);319ASSERT_EQ(newDevice, mDevice);320321// Note that we must call TearDown() before we release the EGL device, since the display322// depends on the device323testTearDown();324325eglReleaseDeviceANGLE(eglDevice);326}327328// Test that calling eglGetPlatformDisplayEXT with the same device returns the same display329TEST_P(EGLDeviceCreationTest, GetPlatformDisplayTwice)330{331CreateD3D11Device();332333EGLDeviceEXT eglDevice =334eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDevice), nullptr);335ASSERT_EGL_SUCCESS();336337// Create an EGLDisplay using the EGLDevice338EGLDisplay display1 = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevice, nullptr);339ASSERT_NE(EGL_NO_DISPLAY, display1);340341EGLDisplay display2 = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevice, nullptr);342ASSERT_NE(EGL_NO_DISPLAY, display2);343344ASSERT_EQ(display1, display2);345346eglTerminate(display1);347eglReleaseDeviceANGLE(eglDevice);348}349350// Test that creating a EGLDeviceEXT from an invalid D3D11 device fails351TEST_P(EGLDeviceCreationTest, InvalidD3D11Device)352{353ANGLE_SKIP_TEST_IF(!mDeviceCreationD3D11ExtAvailable);354355CreateD3D11Device();356357// Use mDeviceContext instead of mDevice358EGLDeviceEXT eglDevice = eglCreateDeviceANGLE(359EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDeviceContext), nullptr);360EXPECT_EQ(EGL_NO_DEVICE_EXT, eglDevice);361EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);362}363364// Test that EGLDeviceEXT holds a ref to the D3D11 device365TEST_P(EGLDeviceCreationTest, D3D11DeviceReferenceCounting)366{367ANGLE_SKIP_TEST_IF(!mDeviceCreationD3D11ExtAvailable);368369CreateD3D11Device();370371EGLDeviceEXT eglDevice =372eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(mDevice), nullptr);373ASSERT_NE(EGL_NO_DEVICE_EXT, eglDevice);374ASSERT_EGL_SUCCESS();375376// Now release our D3D11 device/context377SafeRelease(mDevice);378SafeRelease(mDeviceContext);379380EGLAttrib deviceAttrib;381eglQueryDeviceAttribEXT(eglDevice, EGL_D3D11_DEVICE_ANGLE, &deviceAttrib);382ASSERT_EGL_SUCCESS();383384ID3D11Device *queriedDevice = reinterpret_cast<ID3D11Device *>(deviceAttrib);385ASSERT_EQ(mFeatureLevel, queriedDevice->GetFeatureLevel());386387eglReleaseDeviceANGLE(eglDevice);388}389390// Test that creating a EGLDeviceEXT from a D3D9 device fails391TEST_P(EGLDeviceCreationTest, AnyD3D9Device)392{393ANGLE_SKIP_TEST_IF(!mDeviceCreationD3D11ExtAvailable);394395std::string fakeD3DDevice = "This is a string, not a D3D device";396397EGLDeviceEXT eglDevice = eglCreateDeviceANGLE(398EGL_D3D9_DEVICE_ANGLE, reinterpret_cast<void *>(&fakeD3DDevice), nullptr);399EXPECT_EQ(EGL_NO_DEVICE_EXT, eglDevice);400EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);401}402403class EGLDeviceQueryTest : public ANGLETest404{405protected:406EGLDeviceQueryTest() {}407408void testSetUp() override409{410const char *extensionString =411static_cast<const char *>(eglQueryString(getEGLWindow()->getDisplay(), EGL_EXTENSIONS));412413if (!eglQueryDeviceStringEXT)414{415FAIL() << "ANGLE extension EGL_EXT_device_query export eglQueryDeviceStringEXT was not "416"found";417}418419if (!eglQueryDisplayAttribEXT)420{421FAIL() << "ANGLE extension EGL_EXT_device_query export eglQueryDisplayAttribEXT was "422"not found";423}424425if (!eglQueryDeviceAttribEXT)426{427FAIL() << "ANGLE extension EGL_EXT_device_query export eglQueryDeviceAttribEXT was not "428"found";429}430431EGLAttrib angleDevice = 0;432EXPECT_EGL_TRUE(433eglQueryDisplayAttribEXT(getEGLWindow()->getDisplay(), EGL_DEVICE_EXT, &angleDevice));434extensionString = static_cast<const char *>(435eglQueryDeviceStringEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice), EGL_EXTENSIONS));436if (strstr(extensionString, "EGL_ANGLE_device_d3d") == nullptr)437{438FAIL() << "ANGLE extension EGL_ANGLE_device_d3d was not found";439}440}441};442443// This test attempts to obtain a D3D11 device and a D3D9 device using the eglQueryDeviceAttribEXT444// function.445// If the test is configured to use D3D11 then it should succeed to obtain a D3D11 device.446// If the test is confitured to use D3D9, then it should succeed to obtain a D3D9 device.447TEST_P(EGLDeviceQueryTest, QueryDevice)448{449EGLAttrib device = 0;450EGLAttrib angleDevice = 0;451if (getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)452{453EXPECT_EGL_TRUE(454eglQueryDisplayAttribEXT(getEGLWindow()->getDisplay(), EGL_DEVICE_EXT, &angleDevice));455EXPECT_EGL_TRUE(eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice),456EGL_D3D11_DEVICE_ANGLE, &device));457ID3D11Device *d3d11Device = reinterpret_cast<ID3D11Device *>(device);458IDXGIDevice *dxgiDevice = DynamicCastComObject<IDXGIDevice>(d3d11Device);459EXPECT_TRUE(dxgiDevice != nullptr);460SafeRelease(dxgiDevice);461}462463if (getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE)464{465EXPECT_EGL_TRUE(466eglQueryDisplayAttribEXT(getEGLWindow()->getDisplay(), EGL_DEVICE_EXT, &angleDevice));467EXPECT_EGL_TRUE(eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice),468EGL_D3D9_DEVICE_ANGLE, &device));469IDirect3DDevice9 *d3d9Device = reinterpret_cast<IDirect3DDevice9 *>(device);470IDirect3D9 *d3d9 = nullptr;471EXPECT_EQ(S_OK, d3d9Device->GetDirect3D(&d3d9));472EXPECT_TRUE(d3d9 != nullptr);473SafeRelease(d3d9);474}475}476477// This test attempts to obtain a D3D11 device from a D3D9 configured system and a D3D9 device from478// a D3D11 configured system using the eglQueryDeviceAttribEXT function.479// If the test is configured to use D3D11 then it should fail to obtain a D3D11 device.480// If the test is confitured to use D3D9, then it should fail to obtain a D3D9 device.481TEST_P(EGLDeviceQueryTest, QueryDeviceBadAttribute)482{483EGLAttrib device = 0;484EGLAttrib angleDevice = 0;485if (getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)486{487EXPECT_EGL_TRUE(488eglQueryDisplayAttribEXT(getEGLWindow()->getDisplay(), EGL_DEVICE_EXT, &angleDevice));489EXPECT_EGL_FALSE(eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice),490EGL_D3D9_DEVICE_ANGLE, &device));491}492493if (getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE)494{495EXPECT_EGL_TRUE(496eglQueryDisplayAttribEXT(getEGLWindow()->getDisplay(), EGL_DEVICE_EXT, &angleDevice));497EXPECT_EGL_FALSE(eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice),498EGL_D3D11_DEVICE_ANGLE, &device));499}500}501502// Ensure that:503// - calling getPlatformDisplayEXT using ANGLE_Platform with some parameters504// - extracting the EGLDeviceEXT from the EGLDisplay505// - calling getPlatformDisplayEXT with this EGLDeviceEXT506// results in the same EGLDisplay being returned from getPlatformDisplayEXT both times507TEST_P(EGLDeviceQueryTest, GetPlatformDisplayDeviceReuse)508{509EGLAttrib eglDevice = 0;510EXPECT_EGL_TRUE(511eglQueryDisplayAttribEXT(getEGLWindow()->getDisplay(), EGL_DEVICE_EXT, &eglDevice));512513EGLDisplay display2 = eglGetPlatformDisplayEXT(514EGL_PLATFORM_DEVICE_EXT, reinterpret_cast<EGLDeviceEXT>(eglDevice), nullptr);515EXPECT_EQ(getEGLWindow()->getDisplay(), display2);516}517518// Use this to select which configurations (e.g. which renderer, which GLES major version) these519// tests should be run against.520ANGLE_INSTANTIATE_TEST(EGLDeviceCreationTest, WithNoFixture(ES2_D3D11()));521ANGLE_INSTANTIATE_TEST(EGLDeviceQueryTest, ES2_D3D9(), ES2_D3D11());522523524