#include <gtest/gtest.h>
#include <thread>
#include <vector>
#include "common/Color.h"
#include "common/platform.h"
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
#include "util/EGLWindow.h"
#include "util/OSWindow.h"
#include "util/Timer.h"
#if defined(ANGLE_ENABLE_D3D11)
#define INITGUID
# include <guiddef.h>
# include <d3d11.h>
# include <dcomp.h>
#endif
usingnamespaceangle;
namespace
{
class EGLSurfaceTest : public ANGLETest<>
{ … };
class EGLFloatSurfaceTest : public EGLSurfaceTest
{ … };
class EGLSingleBufferTest : public ANGLETest<>
{ … };
class EGLAndroidAutoRefreshTest : public EGLSingleBufferTest
{ … };
TEST_P(EGLFloatSurfaceTest, Clearing)
{ … }
TEST_P(EGLFloatSurfaceTest, Drawing)
{ … }
class EGLSurfaceTest3 : public EGLSurfaceTest
{ … };
TEST_P(EGLSurfaceTest, MessageLoopBug)
{ … }
TEST_P(EGLSurfaceTest, MessageLoopBugContext)
{ … }
TEST_P(EGLSurfaceTest, MakeCurrentTwice)
{ … }
TEST_P(EGLSurfaceTest, ShrinkWindowThenScissoredClear)
{ … }
TEST_P(EGLSurfaceTest, GrowWindowThenScissoredClear)
{ … }
TEST_P(EGLSurfaceTest3, ShrinkWindowThenScissoredClearBuffer)
{ … }
TEST_P(EGLSurfaceTest, SurfaceUseAfterFreeBug)
{ … }
TEST_P(EGLSurfaceTest, ResizeWindow)
{ … }
TEST_P(EGLSurfaceTest, ResizeWindowWithDraw)
{ … }
TEST_P(EGLSurfaceTest, ResetNativeWindow)
{ … }
TEST_P(EGLSurfaceTest, SwapWithoutAnyDraw)
{ … }
TEST_P(EGLSurfaceTest, CreateWithEGLConfig5650Support)
{ … }
TEST_P(EGLSurfaceTest, CreateWithEGLConfig4444Support)
{ … }
TEST_P(EGLSurfaceTest, CreateWithEGLConfig5551Support)
{ … }
TEST_P(EGLSurfaceTest, CreateWithEGLConfig8880Support)
{ … }
TEST_P(EGLSurfaceTest, CreateWithEGLConfig1010102Support)
{ … }
TEST_P(EGLSurfaceTest, FixedSizeWindow)
{ … }
TEST_P(EGLSurfaceTest3, MakeCurrentDifferentSurfaces)
{ … }
#if defined(ANGLE_ENABLE_D3D11)
class EGLSurfaceTestD3D11 : public EGLSurfaceTest
{
protected:
void testTextureOffset(int offset, UINT pix25, UINT pix75)
{
initializeDisplay();
const EGLint configAttributes[] = {
EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLE_BUFFERS, 0, EGL_NONE};
EGLConfig config;
ASSERT_EGL_TRUE(EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config));
mConfig = config;
initializeMainContext();
EGLAttrib device = 0;
EGLAttrib newEglDevice = 0;
ASSERT_EGL_TRUE(eglQueryDisplayAttribEXT(mDisplay, EGL_DEVICE_EXT, &newEglDevice));
ASSERT_EGL_TRUE(eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(newEglDevice),
EGL_D3D11_DEVICE_ANGLE, &device));
angle::ComPtr<ID3D11Device> d3d11Device(reinterpret_cast<ID3D11Device *>(device));
ASSERT_TRUE(!!d3d11Device);
constexpr UINT kTextureWidth = 100;
constexpr UINT kTextureHeight = 100;
constexpr Color<uint8_t> kOpaqueBlack(0, 0, 0, 255);
std::vector<Color<uint8_t>> textureData(kTextureWidth * kTextureHeight, kOpaqueBlack);
D3D11_SUBRESOURCE_DATA initialData = {};
initialData.pSysMem = textureData.data();
initialData.SysMemPitch = kTextureWidth * sizeof(kOpaqueBlack);
D3D11_TEXTURE2D_DESC desc = {};
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.Width = kTextureWidth;
desc.Height = kTextureHeight;
desc.ArraySize = 1;
desc.MipLevels = 1;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_RENDER_TARGET;
angle::ComPtr<ID3D11Texture2D> texture;
HRESULT hr = d3d11Device->CreateTexture2D(&desc, &initialData, &texture);
ASSERT_TRUE(SUCCEEDED(hr));
angle::ComPtr<ID3D11DeviceContext> d3d11Context;
d3d11Device->GetImmediateContext(&d3d11Context);
const EGLint surfaceAttributes[] = {EGL_WIDTH,
kTextureWidth,
EGL_HEIGHT,
kTextureHeight,
EGL_TEXTURE_OFFSET_X_ANGLE,
offset,
EGL_TEXTURE_OFFSET_Y_ANGLE,
offset,
EGL_NONE};
EGLClientBuffer buffer = reinterpret_cast<EGLClientBuffer>(texture.Get());
mPbufferSurface = eglCreatePbufferFromClientBuffer(mDisplay, EGL_D3D_TEXTURE_ANGLE, buffer,
config, surfaceAttributes);
ASSERT_EGL_SUCCESS();
eglMakeCurrent(mDisplay, mPbufferSurface, mPbufferSurface, mContext);
ASSERT_EGL_SUCCESS();
glClearColor(0, 0, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_EQ(25, 25, 0, 0, pix25, 255);
EXPECT_PIXEL_EQ(75, 75, 0, 0, pix75, 255);
EXPECT_GL_NO_ERROR();
GLuint program = createProgram();
ASSERT_NE(0u, program);
GLint positionLocation =
glGetAttribLocation(program, angle::essl1_shaders::PositionAttrib());
glUseProgram(program);
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);
glDisableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
EXPECT_PIXEL_EQ(25, 25, pix25, 0, 0, 255);
EXPECT_PIXEL_EQ(75, 75, pix75, 0, 0, 255);
EXPECT_GL_NO_ERROR();
glDeleteProgram(program);
EXPECT_GL_NO_ERROR();
GLRenderbuffer renderBuffer;
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 50, 50);
EXPECT_GL_NO_ERROR();
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
renderBuffer);
EXPECT_GL_NO_ERROR();
glClearColor(0, 1, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_EQ(25, 25, 0, 255, 0, 255);
EXPECT_GL_NO_ERROR();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0u);
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
glBlitFramebuffer(0, 0, 50, 50, 0, 0, kTextureWidth, kTextureWidth, GL_COLOR_BUFFER_BIT,
GL_NEAREST);
EXPECT_GL_NO_ERROR();
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0u);
EXPECT_PIXEL_EQ(25, 25, 0, pix25, 0, 255);
EXPECT_PIXEL_EQ(75, 75, 0, pix75, 0, 255);
EXPECT_GL_NO_ERROR();
}
void setupFragCoordOffset(int textureDimension, int offset)
{
ANGLE_SKIP_TEST_IF(!IsEGLClientExtensionEnabled("EGL_ANGLE_platform_angle_d3d"));
initializeDisplay();
EGLAttrib device = 0;
EGLAttrib newEglDevice = 0;
ASSERT_EGL_TRUE(eglQueryDisplayAttribEXT(mDisplay, EGL_DEVICE_EXT, &newEglDevice));
ASSERT_EGL_TRUE(eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(newEglDevice),
EGL_D3D11_DEVICE_ANGLE, &device));
angle::ComPtr<ID3D11Device> d3d11Device(reinterpret_cast<ID3D11Device *>(device));
ASSERT_TRUE(!!d3d11Device);
D3D11_TEXTURE2D_DESC desc = {};
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.Width = textureDimension;
desc.Height = textureDimension;
desc.ArraySize = 1;
desc.MipLevels = 1;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_RENDER_TARGET;
angle::ComPtr<ID3D11Texture2D> texture;
HRESULT hr = d3d11Device->CreateTexture2D(&desc, nullptr, &texture);
ASSERT_TRUE(SUCCEEDED(hr));
const EGLint surfaceAttributes[] = {EGL_WIDTH,
textureDimension,
EGL_HEIGHT,
textureDimension,
EGL_TEXTURE_OFFSET_X_ANGLE,
offset,
EGL_TEXTURE_OFFSET_Y_ANGLE,
offset,
EGL_NONE};
EGLClientBuffer buffer = reinterpret_cast<EGLClientBuffer>(texture.Get());
const EGLint configAttributes[] = {
EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLE_BUFFERS, 0, EGL_NONE};
EGLConfig config;
ASSERT_EGL_TRUE(EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config));
mConfig = config;
mPbufferSurface = eglCreatePbufferFromClientBuffer(mDisplay, EGL_D3D_TEXTURE_ANGLE, buffer,
config, surfaceAttributes);
ASSERT_EGL_SUCCESS();
initializeMainContext();
eglMakeCurrent(mDisplay, mPbufferSurface, mPbufferSurface, mContext);
ASSERT_EGL_SUCCESS();
std::stringstream fs;
fs << "precision mediump float;" << "void main()" << "{" << " float dimension = float("
<< textureDimension << ");" << " float offset = float(" << offset << ");"
<< " gl_FragColor = vec4((gl_FragCoord.x + offset - 0.5) / dimension,"
<< " (gl_FragCoord.y + offset - 0.5) / dimension,"
<< " gl_FragCoord.z,"
<< " gl_FragCoord.w);" << "}";
GLuint program = createProgram(fs.str().c_str());
ASSERT_NE(0u, program);
glUseProgram(program);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
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,
};
GLint positionLocation =
glGetAttribLocation(program, angle::essl1_shaders::PositionAttrib());
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(positionLocation);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(positionLocation);
glDeleteProgram(program);
EXPECT_GL_NO_ERROR();
}
};
TEST_P(EGLSurfaceTestD3D11, CreateDirectCompositionSurface)
{
ANGLE_SKIP_TEST_IF(!IsEGLClientExtensionEnabled("EGL_ANGLE_platform_angle_d3d"));
initializeDisplay();
EGLAttrib device = 0;
EGLAttrib newEglDevice = 0;
ASSERT_EGL_TRUE(eglQueryDisplayAttribEXT(mDisplay, EGL_DEVICE_EXT, &newEglDevice));
ASSERT_EGL_TRUE(eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(newEglDevice),
EGL_D3D11_DEVICE_ANGLE, &device));
angle::ComPtr<ID3D11Device> d3d11Device(reinterpret_cast<ID3D11Device *>(device));
ASSERT_TRUE(!!d3d11Device);
HMODULE dcompLibrary = LoadLibraryA("dcomp.dll");
if (!dcompLibrary)
{
std::cout << "DirectComposition not supported" << std::endl;
return;
}
typedef HRESULT(WINAPI * PFN_DCOMPOSITION_CREATE_DEVICE2)(IUnknown * dxgiDevice, REFIID iid,
void **dcompositionDevice);
PFN_DCOMPOSITION_CREATE_DEVICE2 createDComp = reinterpret_cast<PFN_DCOMPOSITION_CREATE_DEVICE2>(
GetProcAddress(dcompLibrary, "DCompositionCreateDevice2"));
if (!createDComp)
{
std::cout << "DirectComposition2 not supported" << std::endl;
FreeLibrary(dcompLibrary);
return;
}
angle::ComPtr<IDCompositionDevice> dcompDevice;
HRESULT hr = createDComp(d3d11Device.Get(), IID_PPV_ARGS(dcompDevice.GetAddressOf()));
ASSERT_TRUE(SUCCEEDED(hr));
angle::ComPtr<IDCompositionSurface> dcompSurface;
hr = dcompDevice->CreateSurface(100, 100, DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_ALPHA_MODE_PREMULTIPLIED, dcompSurface.GetAddressOf());
ASSERT_TRUE(SUCCEEDED(hr));
angle::ComPtr<ID3D11Texture2D> texture;
POINT updateOffset;
hr = dcompSurface->BeginDraw(nullptr, IID_PPV_ARGS(texture.GetAddressOf()), &updateOffset);
ASSERT_TRUE(SUCCEEDED(hr));
const EGLint configAttributes[] = {
EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLE_BUFFERS, 0, EGL_NONE};
EGLConfig config;
ASSERT_EGL_TRUE(EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config));
const EGLint surfaceAttributes[] = {EGL_WIDTH,
100,
EGL_HEIGHT,
100,
EGL_TEXTURE_OFFSET_X_ANGLE,
updateOffset.x,
EGL_TEXTURE_OFFSET_Y_ANGLE,
updateOffset.y,
EGL_NONE};
EGLClientBuffer buffer = reinterpret_cast<EGLClientBuffer>(texture.Get());
mPbufferSurface = eglCreatePbufferFromClientBuffer(mDisplay, EGL_D3D_TEXTURE_ANGLE, buffer,
config, surfaceAttributes);
ASSERT_EGL_SUCCESS();
mConfig = config;
initializeMainContext();
eglMakeCurrent(mDisplay, mPbufferSurface, mPbufferSurface, mContext);
ASSERT_EGL_SUCCESS();
GLuint program = createProgram();
ASSERT_NE(0u, program);
drawWithProgram(program);
EXPECT_GL_NO_ERROR();
glDeleteProgram(program);
}
TEST_P(EGLSurfaceTestD3D11, CreateSurfaceWithTextureNegativeOffset)
{
ANGLE_SKIP_TEST_IF(!IsEGLClientExtensionEnabled("EGL_ANGLE_platform_angle_d3d"));
testTextureOffset(-50, 255, 0);
}
TEST_P(EGLSurfaceTestD3D11, CreateSurfaceWithTextureOffset)
{
ANGLE_SKIP_TEST_IF(!IsEGLClientExtensionEnabled("EGL_ANGLE_platform_angle_d3d"));
testTextureOffset(50, 0, 255);
}
TEST_P(EGLSurfaceTestD3D11, CreateSurfaceWithMSAA)
{
ANGLE_SKIP_TEST_IF(!IsEGLClientExtensionEnabled("EGL_ANGLE_platform_angle_d3d"));
const EGLint configAttributes[] =
{
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 0,
EGL_DEPTH_SIZE, 0,
EGL_STENCIL_SIZE, 0,
EGL_SAMPLE_BUFFERS, 1,
EGL_SAMPLES, 4,
EGL_NONE
};
initializeDisplay();
EGLConfig config;
if (EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config) == EGL_FALSE)
{
std::cout << "EGLConfig for 4xMSAA is not supported, skipping test" << std::endl;
return;
}
initializeSurface(config);
initializeMainContext();
eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
ASSERT_EGL_SUCCESS();
GLuint program = createProgram();
ASSERT_NE(0u, program);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
GLint positionLocation = glGetAttribLocation(program, angle::essl1_shaders::PositionAttrib());
ASSERT_NE(-1, positionLocation);
glUseProgram(program);
const GLfloat halfPixelOffset = 0.5f * 2.0f / mOSWindow->getWidth();
const GLfloat vertices[] =
{
-1.0f + halfPixelOffset, 1.0f, 0.5f,
-1.0f + halfPixelOffset, -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, 3);
glDisableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
EXPECT_PIXEL_NEAR(0, 0, 127, 0, 0, 255, 10);
EXPECT_GL_NO_ERROR();
glDeleteProgram(program);
}
TEST_P(EGLSurfaceTestD3D11, FragCoordOffset)
{
constexpr int kTextureDimension = 28;
constexpr int kOffset = 6;
setupFragCoordOffset(kTextureDimension, kOffset);
for (int x = 0; x < kOffset; x++)
{
for (int y = 0; y < kOffset; y++)
{
EXPECT_PIXEL_EQ(x, y, 0, 0, 0, 0);
}
}
for (int x = kOffset; x < kTextureDimension; x++)
{
for (int y = kOffset; y < kTextureDimension; y++)
{
EXPECT_PIXEL_NEAR(x, y, x * 255.0 / kTextureDimension, y * 255.0 / kTextureDimension,
191, 255, 0.5);
}
}
}
TEST_P(EGLSurfaceTestD3D11, FragCoordOffsetNegative)
{
constexpr int kTextureDimension = 28;
constexpr int kOffset = 6;
setupFragCoordOffset(kTextureDimension, -kOffset);
for (int x = kTextureDimension - kOffset; x < kTextureDimension; x++)
{
for (int y = kTextureDimension - kOffset; y < kTextureDimension; y++)
{
EXPECT_PIXEL_EQ(x, y, 0, 0, 0, 0);
}
}
for (int x = 0; x < kTextureDimension - kOffset; x++)
{
for (int y = 0; y < kTextureDimension - kOffset; y++)
{
EXPECT_PIXEL_NEAR(x, y, x * 255.0 / kTextureDimension, y * 255.0 / kTextureDimension,
191, 255, 0.5);
}
}
}
#endif
TEST_P(EGLSurfaceTest3, BlitBetweenSurfaces)
{ … }
TEST_P(EGLSurfaceTest3, BlitBetweenSurfacesWithDeferredClear)
{ … }
TEST_P(EGLSurfaceTest, RobustResourceInitAndEmulatedAlpha)
{ … }
void EGLSurfaceTest::drawQuadThenTearDown()
{ … }
TEST_P(EGLSurfaceTest, CreateSurfaceSwapIntervalANGLE)
{ … }
TEST_P(EGLSurfaceTest, TimestampSurfaceAttribute)
{ … }
TEST_P(EGLSingleBufferTest, OnCreateWindowSurface)
{ … }
TEST_P(EGLSingleBufferTest, OnSetSurfaceAttrib)
{ … }
uint32_t EGLSingleBufferTest::drawAndSwap(EGLSurface &surface,
EGLDisplay &display,
uint32_t color,
bool flush)
{ … }
TEST_P(EGLSingleBufferTest, MutableRenderBuffer)
{ … }
TEST_P(EGLSingleBufferTest, SharedPresentBarrier)
{ … }
TEST_P(EGLSingleBufferTest, ScissoredClear)
{ … }
TEST_P(EGLSingleBufferTest, ScissoredDraw)
{ … }
TEST_P(EGLSingleBufferTest, WaitOneOffSubmission)
{ … }
TEST_P(EGLAndroidAutoRefreshTest, Basic)
{ … }
void EGLSurfaceTest::runWaitSemaphoreTest(bool useSecondContext)
{ … }
TEST_P(EGLSurfaceTest, DISABLED_WaitSemaphoreAddedAfterCommands)
{ … }
TEST_P(EGLSurfaceTest, DISABLED_CommandsSubmittedWithoutWaitSemaphore)
{ … }
void EGLSurfaceTest::runDestroyNotCurrentSurfaceTest(bool testWindowsSurface)
{ … }
TEST_P(EGLSurfaceTest, DestroyNotCurrentPbufferSurface)
{ … }
TEST_P(EGLSurfaceTest, DestroyNotCurrentWindowSurface)
{ … }
TEST_P(EGLSurfaceTest, DISABLED_RandomClearTearing)
{ … }
TEST_P(EGLSurfaceTest, DestroyAndRecreateWhileCurrent)
{ … }
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(…);
ANGLE_INSTANTIATE_TEST(…);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(…);
ANGLE_INSTANTIATE_TEST(…);
ANGLE_INSTANTIATE_TEST(…);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(…);
ANGLE_INSTANTIATE_TEST(…);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(…);
ANGLE_INSTANTIATE_TEST(…);
#if defined(ANGLE_ENABLE_D3D11)
ANGLE_INSTANTIATE_TEST(EGLSurfaceTestD3D11, WithNoFixture(ES2_D3D11()), WithNoFixture(ES3_D3D11()));
#endif