diff options
Diffstat (limited to 'gfx/angle/src/tests/egl_tests/EGLPresentPathD3D11Test.cpp')
-rwxr-xr-x | gfx/angle/src/tests/egl_tests/EGLPresentPathD3D11Test.cpp | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/gfx/angle/src/tests/egl_tests/EGLPresentPathD3D11Test.cpp b/gfx/angle/src/tests/egl_tests/EGLPresentPathD3D11Test.cpp new file mode 100755 index 000000000..c73c7c4ff --- /dev/null +++ b/gfx/angle/src/tests/egl_tests/EGLPresentPathD3D11Test.cpp @@ -0,0 +1,378 @@ +// +// Copyright 2015 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. +// + +#include "test_utils/ANGLETest.h" + +#include <cstdint> +#include "com_utils.h" +#include "OSWindow.h" +#include <d3d11.h> + +using namespace angle; + +class EGLPresentPathD3D11 : public testing::TestWithParam<PlatformParameters> +{ + protected: + EGLPresentPathD3D11() + : mDisplay(EGL_NO_DISPLAY), + mContext(EGL_NO_CONTEXT), + mSurface(EGL_NO_SURFACE), + mOffscreenSurfaceD3D11Texture(nullptr), + mConfig(0), + mOSWindow(nullptr), + mWindowWidth(0) + { + } + + void SetUp() override + { + mOSWindow = CreateOSWindow(); + mWindowWidth = 64; + mOSWindow->initialize("EGLPresentPathD3D11", mWindowWidth, mWindowWidth); + } + + void initializeEGL(bool usePresentPathFast) + { + int clientVersion = GetParam().majorVersion; + + const char *extensionString = + static_cast<const char *>(eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS)); + ASSERT_NE(nullptr, strstr(extensionString, "EGL_ANGLE_experimental_present_path")); + + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = + reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>( + eglGetProcAddress("eglGetPlatformDisplayEXT")); + ASSERT_NE(nullptr, eglGetPlatformDisplayEXT); + + // Set up EGL Display + EGLint displayAttribs[] = { + EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(), + EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, GetParam().eglParameters.majorVersion, + EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, GetParam().eglParameters.majorVersion, + EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE, + usePresentPathFast ? EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE + : EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE, + EGL_NONE}; + mDisplay = + eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, displayAttribs); + ASSERT_TRUE(EGL_NO_DISPLAY != mDisplay); + ASSERT_EGL_TRUE(eglInitialize(mDisplay, NULL, NULL)); + + // Choose the EGL config + EGLint numConfigs; + EGLint configAttribs[] = {EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_ALPHA_SIZE, + 8, + EGL_RENDERABLE_TYPE, + clientVersion == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, + EGL_PBUFFER_BIT, + EGL_NONE}; + ASSERT_EGL_TRUE(eglChooseConfig(mDisplay, configAttribs, &mConfig, 1, &numConfigs)); + ASSERT_EQ(1, numConfigs); + + // Set up the EGL context + EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, clientVersion, EGL_NONE}; + mContext = eglCreateContext(mDisplay, mConfig, NULL, contextAttribs); + ASSERT_TRUE(EGL_NO_CONTEXT != mContext); + } + + void createWindowSurface() + { + mSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), nullptr); + } + + void createPbufferFromClientBufferSurface() + { + EGLAttrib device = 0; + EGLAttrib angleDevice = 0; + + PFNEGLQUERYDISPLAYATTRIBEXTPROC queryDisplayAttribEXT; + PFNEGLQUERYDEVICEATTRIBEXTPROC queryDeviceAttribEXT; + + const char *extensionString = + static_cast<const char *>(eglQueryString(mDisplay, EGL_EXTENSIONS)); + EXPECT_TRUE(strstr(extensionString, "EGL_EXT_device_query")); + + queryDisplayAttribEXT = + (PFNEGLQUERYDISPLAYATTRIBEXTPROC)eglGetProcAddress("eglQueryDisplayAttribEXT"); + queryDeviceAttribEXT = + (PFNEGLQUERYDEVICEATTRIBEXTPROC)eglGetProcAddress("eglQueryDeviceAttribEXT"); + ASSERT_NE(nullptr, queryDisplayAttribEXT); + ASSERT_NE(nullptr, queryDeviceAttribEXT); + + ASSERT_EGL_TRUE(queryDisplayAttribEXT(mDisplay, EGL_DEVICE_EXT, &angleDevice)); + ASSERT_EGL_TRUE(queryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice), + EGL_D3D11_DEVICE_ANGLE, &device)); + ID3D11Device *d3d11Device = reinterpret_cast<ID3D11Device *>(device); + + D3D11_TEXTURE2D_DESC textureDesc = {0}; + textureDesc.Width = mWindowWidth; + textureDesc.Height = mWindowWidth; + textureDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + textureDesc.MipLevels = 1; + textureDesc.ArraySize = 1; + textureDesc.SampleDesc.Count = 1; + textureDesc.SampleDesc.Quality = 0; + textureDesc.Usage = D3D11_USAGE_DEFAULT; + textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + textureDesc.CPUAccessFlags = 0; + textureDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED; + + ASSERT_TRUE(SUCCEEDED( + d3d11Device->CreateTexture2D(&textureDesc, nullptr, &mOffscreenSurfaceD3D11Texture))); + + IDXGIResource *dxgiResource = + DynamicCastComObject<IDXGIResource>(mOffscreenSurfaceD3D11Texture); + ASSERT_NE(nullptr, dxgiResource); + + HANDLE sharedHandle = 0; + ASSERT_TRUE(SUCCEEDED(dxgiResource->GetSharedHandle(&sharedHandle))); + SafeRelease(dxgiResource); + + EGLint pBufferAttributes[] = {EGL_WIDTH, mWindowWidth, EGL_HEIGHT, + mWindowWidth, EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, EGL_NONE}; + + mSurface = eglCreatePbufferFromClientBuffer(mDisplay, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, + sharedHandle, mConfig, pBufferAttributes); + ASSERT_TRUE(EGL_NO_SURFACE != mSurface); + } + + void makeCurrent() { ASSERT_EGL_TRUE(eglMakeCurrent(mDisplay, mSurface, mSurface, mContext)); } + + void TearDown() override + { + SafeRelease(mOffscreenSurfaceD3D11Texture); + + if (mDisplay != EGL_NO_DISPLAY) + { + eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + if (mSurface != EGL_NO_SURFACE) + { + eglDestroySurface(mDisplay, mSurface); + mSurface = EGL_NO_SURFACE; + } + + if (mContext != EGL_NO_CONTEXT) + { + eglDestroyContext(mDisplay, mContext); + mContext = EGL_NO_CONTEXT; + } + + eglTerminate(mDisplay); + mDisplay = EGL_NO_DISPLAY; + } + + mOSWindow->destroy(); + SafeDelete(mOSWindow); + } + + void drawQuadUsingGL() + { + GLuint m2DProgram; + GLint mTexture2DUniformLocation; + + const std::string vertexShaderSource = + SHADER_SOURCE(precision highp float; attribute vec4 position; varying vec2 texcoord; + + void main() + { + gl_Position = vec4(position.xy, 0.0, 1.0); + texcoord = (position.xy * 0.5) + 0.5; + }); + + const std::string fragmentShaderSource2D = + SHADER_SOURCE(precision highp float; uniform sampler2D tex; varying vec2 texcoord; + + void main() + { + gl_FragColor = texture2D(tex, texcoord); + }); + + m2DProgram = CompileProgram(vertexShaderSource, fragmentShaderSource2D); + mTexture2DUniformLocation = glGetUniformLocation(m2DProgram, "tex"); + + uint8_t textureInitData[16] = { + 255, 0, 0, 255, // Red + 0, 255, 0, 255, // Green + 0, 0, 255, 255, // Blue + 255, 255, 0, 255 // Red + Green + }; + + // Create a simple RGBA texture + GLuint tex = 0; + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, + textureInitData); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + ASSERT_GL_NO_ERROR(); + + // Draw a quad using the texture + glClear(GL_COLOR_BUFFER_BIT); + glUseProgram(m2DProgram); + glUniform1i(mTexture2DUniformLocation, 0); + + GLint positionLocation = glGetAttribLocation(m2DProgram, "position"); + glUseProgram(m2DProgram); + const GLfloat vertices[] = + { + -1.0f, 1.0f, 0.5f, + -1.0f, -1.0f, 0.5f, + 1.0f, -1.0f, 0.5f, + -1.0f, 1.0f, 0.5f, + 1.0f, -1.0f, 0.5f, + 1.0f, 1.0f, 0.5f, + }; + + glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices); + glEnableVertexAttribArray(positionLocation); + + glDrawArrays(GL_TRIANGLES, 0, 6); + ASSERT_GL_NO_ERROR(); + + glDeleteProgram(m2DProgram); + } + + void checkPixelsUsingGL() + { + // Note that the texture is in BGRA format + EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255); // Red + EXPECT_PIXEL_EQ(mWindowWidth - 1, 0, 0, 255, 0, 255); // Green + EXPECT_PIXEL_EQ(0, mWindowWidth - 1, 0, 0, 255, 255); // Blue + EXPECT_PIXEL_EQ(mWindowWidth - 1, mWindowWidth - 1, 255, 255, 0, 255); // Red + green + } + + void checkPixelsUsingD3D(bool usingPresentPathFast) + { + ASSERT_NE(nullptr, mOffscreenSurfaceD3D11Texture); + + D3D11_TEXTURE2D_DESC textureDesc = {0}; + ID3D11Device *device; + ID3D11DeviceContext *context; + mOffscreenSurfaceD3D11Texture->GetDesc(&textureDesc); + mOffscreenSurfaceD3D11Texture->GetDevice(&device); + device->GetImmediateContext(&context); + ASSERT_NE(nullptr, device); + ASSERT_NE(nullptr, context); + + textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + textureDesc.Usage = D3D11_USAGE_STAGING; + textureDesc.BindFlags = 0; + textureDesc.MiscFlags = 0; + ID3D11Texture2D *cpuTexture = nullptr; + ASSERT_TRUE(SUCCEEDED(device->CreateTexture2D(&textureDesc, nullptr, &cpuTexture))); + + context->CopyResource(cpuTexture, mOffscreenSurfaceD3D11Texture); + + D3D11_MAPPED_SUBRESOURCE mappedSubresource; + context->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mappedSubresource); + ASSERT_EQ(static_cast<UINT>(mWindowWidth * 4), mappedSubresource.RowPitch); + ASSERT_EQ(static_cast<UINT>(mWindowWidth * mWindowWidth * 4), mappedSubresource.DepthPitch); + + angle::GLColor *byteData = reinterpret_cast<angle::GLColor *>(mappedSubresource.pData); + + // Note that the texture is in BGRA format, although the GLColor struct is RGBA + GLColor expectedTopLeftPixel = GLColor(0, 0, 255, 255); // Red + GLColor expectedTopRightPixel = GLColor(0, 255, 0, 255); // Green + GLColor expectedBottomLeftPixel = GLColor(255, 0, 0, 255); // Blue + GLColor expectedBottomRightPixel = GLColor(0, 255, 255, 255); // Red + Green + + if (usingPresentPathFast) + { + // Invert the expected values + GLColor tempTopLeft = expectedTopLeftPixel; + GLColor tempTopRight = expectedTopRightPixel; + expectedTopLeftPixel = expectedBottomLeftPixel; + expectedTopRightPixel = expectedBottomRightPixel; + expectedBottomLeftPixel = tempTopLeft; + expectedBottomRightPixel = tempTopRight; + } + + EXPECT_EQ(expectedTopLeftPixel, byteData[0]); + EXPECT_EQ(expectedTopRightPixel, byteData[(mWindowWidth - 1)]); + EXPECT_EQ(expectedBottomLeftPixel, byteData[(mWindowWidth - 1) * mWindowWidth]); + EXPECT_EQ(expectedBottomRightPixel, + byteData[(mWindowWidth - 1) * mWindowWidth + (mWindowWidth - 1)]); + + context->Unmap(cpuTexture, 0); + SafeRelease(cpuTexture); + SafeRelease(device); + SafeRelease(context); + } + + EGLDisplay mDisplay; + EGLContext mContext; + EGLSurface mSurface; + ID3D11Texture2D *mOffscreenSurfaceD3D11Texture; + EGLConfig mConfig; + OSWindow *mOSWindow; + GLint mWindowWidth; +}; + +// Test that rendering basic content onto a window surface when present path fast +// is enabled works as expected +TEST_P(EGLPresentPathD3D11, WindowPresentPathFast) +{ + initializeEGL(true); + createWindowSurface(); + makeCurrent(); + + drawQuadUsingGL(); + + checkPixelsUsingGL(); +} + +// Test that rendering basic content onto a client buffer surface when present path fast +// works as expected, and is also oriented the correct way around +TEST_P(EGLPresentPathD3D11, ClientBufferPresentPathFast) +{ + initializeEGL(true); + createPbufferFromClientBufferSurface(); + makeCurrent(); + + drawQuadUsingGL(); + + checkPixelsUsingGL(); + checkPixelsUsingD3D(true); +} + +// Test that rendering basic content onto a window surface when present path fast +// is disabled works as expected +TEST_P(EGLPresentPathD3D11, WindowPresentPathCopy) +{ + initializeEGL(false); + createWindowSurface(); + makeCurrent(); + + drawQuadUsingGL(); + + checkPixelsUsingGL(); +} + +// Test that rendering basic content onto a client buffer surface when present path +// fast is disabled works as expected, and is also oriented the correct way around +TEST_P(EGLPresentPathD3D11, ClientBufferPresentPathCopy) +{ + initializeEGL(false); + createPbufferFromClientBufferSurface(); + makeCurrent(); + + drawQuadUsingGL(); + + checkPixelsUsingGL(); + checkPixelsUsingD3D(false); +} + +ANGLE_INSTANTIATE_TEST(EGLPresentPathD3D11, ES2_D3D11(), ES2_D3D11_FL9_3());
\ No newline at end of file |