blob: fd310a014eed89a06506f84b48b280a8081f9bf8 [file] [log] [blame]
//
// 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.
//
// ANGLETest:
// Implementation of common ANGLE testing fixture.
//
#include "ANGLETest.h"
#include "EGLWindow.h"
#include "OSWindow.h"
namespace angle
{
const GLColorRGB GLColorRGB::black(0u, 0u, 0u);
const GLColorRGB GLColorRGB::blue(0u, 0u, 255u);
const GLColorRGB GLColorRGB::green(0u, 255u, 0u);
const GLColorRGB GLColorRGB::red(255u, 0u, 0u);
const GLColorRGB GLColorRGB::yellow(255u, 255u, 0);
const GLColor GLColor::black = GLColor(0u, 0u, 0u, 255u);
const GLColor GLColor::blue = GLColor(0u, 0u, 255u, 255u);
const GLColor GLColor::cyan = GLColor(0u, 255u, 255u, 255u);
const GLColor GLColor::green = GLColor(0u, 255u, 0u, 255u);
const GLColor GLColor::red = GLColor(255u, 0u, 0u, 255u);
const GLColor GLColor::transparentBlack = GLColor(0u, 0u, 0u, 0u);
const GLColor GLColor::white = GLColor(255u, 255u, 255u, 255u);
const GLColor GLColor::yellow = GLColor(255u, 255u, 0, 255u);
const GLColor GLColor::magenta = GLColor(255u, 0u, 255u, 255u);
namespace
{
float ColorNorm(GLubyte channelValue)
{
return static_cast<float>(channelValue) / 255.0f;
}
GLubyte ColorDenorm(float colorValue)
{
return static_cast<GLubyte>(colorValue * 255.0f);
}
void TestPlatform_logError(PlatformMethods *platform, const char *errorMessage)
{
auto *testPlatformContext = static_cast<TestPlatformContext *>(platform->context);
if (testPlatformContext->ignoreMessages)
return;
FAIL() << errorMessage;
}
void TestPlatform_logWarning(PlatformMethods *platform, const char *warningMessage)
{
auto *testPlatformContext = static_cast<TestPlatformContext *>(platform->context);
if (testPlatformContext->ignoreMessages)
return;
std::cerr << "Warning: " << warningMessage << std::endl;
}
void TestPlatform_logInfo(PlatformMethods *platform, const char *infoMessage)
{
auto *testPlatformContext = static_cast<TestPlatformContext *>(platform->context);
if (testPlatformContext->ignoreMessages)
return;
WriteDebugMessage("%s\n", infoMessage);
}
void TestPlatform_overrideWorkaroundsD3D(PlatformMethods *platform, WorkaroundsD3D *workaroundsD3D)
{
auto *testPlatformContext = static_cast<TestPlatformContext *>(platform->context);
if (testPlatformContext->currentTest)
{
testPlatformContext->currentTest->overrideWorkaroundsD3D(workaroundsD3D);
}
}
void TestPlatform_overrideFeaturesVk(PlatformMethods *platform, FeaturesVk *workaroundsVulkan)
{
auto *testPlatformContext = static_cast<TestPlatformContext *>(platform->context);
if (testPlatformContext->currentTest)
{
testPlatformContext->currentTest->overrideFeaturesVk(workaroundsVulkan);
}
}
const std::array<Vector3, 6> kQuadVertices = {{
Vector3(-1.0f, 1.0f, 0.5f),
Vector3(-1.0f, -1.0f, 0.5f),
Vector3(1.0f, -1.0f, 0.5f),
Vector3(-1.0f, 1.0f, 0.5f),
Vector3(1.0f, -1.0f, 0.5f),
Vector3(1.0f, 1.0f, 0.5f),
}};
const std::array<Vector3, 4> kIndexedQuadVertices = {{
Vector3(-1.0f, 1.0f, 0.5f),
Vector3(-1.0f, -1.0f, 0.5f),
Vector3(1.0f, -1.0f, 0.5f),
Vector3(1.0f, 1.0f, 0.5f),
}};
constexpr std::array<GLushort, 6> kIndexedQuadIndices = {{0, 1, 2, 0, 2, 3}};
const char *GetColorName(GLColor color)
{
if (color == GLColor::red)
{
return "Red";
}
if (color == GLColor::green)
{
return "Green";
}
if (color == GLColor::blue)
{
return "Blue";
}
if (color == GLColor::white)
{
return "White";
}
if (color == GLColor::black)
{
return "Black";
}
if (color == GLColor::transparentBlack)
{
return "Transparent Black";
}
if (color == GLColor::yellow)
{
return "Yellow";
}
if (color == GLColor::magenta)
{
return "Magenta";
}
if (color == GLColor::cyan)
{
return "Cyan";
}
return nullptr;
}
} // anonymous namespace
GLColorRGB::GLColorRGB() : R(0), G(0), B(0) {}
GLColorRGB::GLColorRGB(GLubyte r, GLubyte g, GLubyte b) : R(r), G(g), B(b) {}
GLColorRGB::GLColorRGB(const Vector3 &floatColor)
: R(ColorDenorm(floatColor.x())), G(ColorDenorm(floatColor.y())), B(ColorDenorm(floatColor.z()))
{}
GLColor::GLColor() : R(0), G(0), B(0), A(0) {}
GLColor::GLColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a) : R(r), G(g), B(b), A(a) {}
GLColor::GLColor(const Vector4 &floatColor)
: R(ColorDenorm(floatColor.x())),
G(ColorDenorm(floatColor.y())),
B(ColorDenorm(floatColor.z())),
A(ColorDenorm(floatColor.w()))
{}
GLColor::GLColor(GLuint colorValue) : R(0), G(0), B(0), A(0)
{
memcpy(&R, &colorValue, sizeof(GLuint));
}
testing::AssertionResult GLColor::ExpectNear(const GLColor &expected, const GLColor &err) const
{
testing::AssertionResult result(
abs(int(expected.R) - this->R) <= err.R && abs(int(expected.G) - this->G) <= err.G &&
abs(int(expected.B) - this->B) <= err.B && abs(int(expected.A) - this->A) <= err.A);
if (!bool(result))
{
result << "Expected " << expected << "+/-" << err << ", was " << *this;
}
return result;
}
void CreatePixelCenterWindowCoords(const std::vector<Vector2> &pixelPoints,
int windowWidth,
int windowHeight,
std::vector<Vector3> *outVertices)
{
for (Vector2 pixelPoint : pixelPoints)
{
outVertices->emplace_back(Vector3((pixelPoint[0] + 0.5f) * 2.0f / windowWidth - 1.0f,
(pixelPoint[1] + 0.5f) * 2.0f / windowHeight - 1.0f,
0.0f));
}
}
Vector4 GLColor::toNormalizedVector() const
{
return Vector4(ColorNorm(R), ColorNorm(G), ColorNorm(B), ColorNorm(A));
}
GLColor ReadColor(GLint x, GLint y)
{
GLColor actual;
glReadPixels((x), (y), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &actual.R);
EXPECT_GL_NO_ERROR();
return actual;
}
bool operator==(const GLColor &a, const GLColor &b)
{
return a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A;
}
bool operator!=(const GLColor &a, const GLColor &b)
{
return !(a == b);
}
std::ostream &operator<<(std::ostream &ostream, const GLColor &color)
{
const char *colorName = GetColorName(color);
if (colorName)
{
return ostream << colorName;
}
ostream << "(" << static_cast<unsigned int>(color.R) << ", "
<< static_cast<unsigned int>(color.G) << ", " << static_cast<unsigned int>(color.B)
<< ", " << static_cast<unsigned int>(color.A) << ")";
return ostream;
}
bool operator==(const GLColor32F &a, const GLColor32F &b)
{
return a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A;
}
std::ostream &operator<<(std::ostream &ostream, const GLColor32F &color)
{
ostream << "(" << color.R << ", " << color.G << ", " << color.B << ", " << color.A << ")";
return ostream;
}
GLColor32F ReadColor32F(GLint x, GLint y)
{
GLColor32F actual;
glReadPixels((x), (y), 1, 1, GL_RGBA, GL_FLOAT, &actual.R);
EXPECT_GL_NO_ERROR();
return actual;
}
} // namespace angle
// static
std::array<angle::Vector3, 6> ANGLETestBase::GetQuadVertices()
{
return angle::kQuadVertices;
}
// static
std::array<GLushort, 6> ANGLETestBase::GetQuadIndices()
{
return angle::kIndexedQuadIndices;
}
// static
std::array<angle::Vector3, 4> ANGLETestBase::GetIndexedQuadVertices()
{
return angle::kIndexedQuadVertices;
}
ANGLETestBase::ANGLETestBase(const angle::PlatformParameters &params)
: mEGLWindow(nullptr),
mWidth(16),
mHeight(16),
mIgnoreD3D11SDKLayersWarnings(false),
mQuadVertexBuffer(0),
mQuadIndexBuffer(0),
m2DTexturedQuadProgram(0),
m3DTexturedQuadProgram(0),
mDeferContextInit(false)
{
mEGLWindow = new EGLWindow(params.majorVersion, params.minorVersion, params.eglParameters);
// Default debug layers to enabled in tests.
mEGLWindow->setDebugLayersEnabled(true);
// Workaround for NVIDIA not being able to share OpenGL and Vulkan contexts.
EGLint renderer = params.getRenderer();
bool needsWindowSwap = mLastRendererType.valid() &&
((renderer != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) !=
(mLastRendererType.value() != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE));
if (needsWindowSwap)
{
DestroyTestWindow();
if (!InitTestWindow())
{
std::cerr << "Failed to create ANGLE test window.";
}
}
mLastRendererType = renderer;
}
ANGLETestBase::~ANGLETestBase()
{
if (mQuadVertexBuffer)
{
glDeleteBuffers(1, &mQuadVertexBuffer);
}
if (mQuadIndexBuffer)
{
glDeleteBuffers(1, &mQuadIndexBuffer);
}
if (m2DTexturedQuadProgram)
{
glDeleteProgram(m2DTexturedQuadProgram);
}
if (m3DTexturedQuadProgram)
{
glDeleteProgram(m3DTexturedQuadProgram);
}
SafeDelete(mEGLWindow);
}
void ANGLETestBase::ANGLETestSetUp()
{
mPlatformContext.ignoreMessages = false;
mPlatformContext.currentTest = this;
// Resize the window before creating the context so that the first make current
// sets the viewport and scissor box to the right size.
bool needSwap = false;
if (mOSWindow->getWidth() != mWidth || mOSWindow->getHeight() != mHeight)
{
if (!mOSWindow->resize(mWidth, mHeight))
{
FAIL() << "Failed to resize ANGLE test window.";
}
needSwap = true;
}
mPlatformMethods.overrideWorkaroundsD3D = angle::TestPlatform_overrideWorkaroundsD3D;
mPlatformMethods.overrideFeaturesVk = angle::TestPlatform_overrideFeaturesVk;
mPlatformMethods.logError = angle::TestPlatform_logError;
mPlatformMethods.logWarning = angle::TestPlatform_logWarning;
mPlatformMethods.logInfo = angle::TestPlatform_logInfo;
mPlatformMethods.context = &mPlatformContext;
mEGLWindow->setPlatformMethods(&mPlatformMethods);
if (!mEGLWindow->initializeDisplayAndSurface(mOSWindow))
{
FAIL() << "egl display or surface init failed.";
}
if (!mDeferContextInit && !mEGLWindow->initializeContext())
{
FAIL() << "GL Context init failed.";
}
if (needSwap)
{
// Swap the buffers so that the default framebuffer picks up the resize
// which will allow follow-up test code to assume the framebuffer covers
// the whole window.
swapBuffers();
}
// This Viewport command is not strictly necessary but we add it so that programs
// taking OpenGL traces can guess the size of the default framebuffer and show it
// in their UIs
glViewport(0, 0, mWidth, mHeight);
const auto &info = testing::UnitTest::GetInstance()->current_test_info();
angle::WriteDebugMessage("Entering %s.%s\n", info->test_case_name(), info->name());
}
void ANGLETestBase::ANGLETestTearDown()
{
mEGLWindow->setPlatformMethods(nullptr);
mPlatformContext.currentTest = nullptr;
checkD3D11SDKLayersMessages();
const auto &info = testing::UnitTest::GetInstance()->current_test_info();
angle::WriteDebugMessage("Exiting %s.%s\n", info->test_case_name(), info->name());
swapBuffers();
if (eglGetError() != EGL_SUCCESS)
{
FAIL() << "egl error during swap.";
}
mOSWindow->messageLoop();
if (!destroyEGLContext())
{
FAIL() << "egl context destruction failed.";
}
// Check for quit message
Event myEvent;
while (mOSWindow->popEvent(&myEvent))
{
if (myEvent.Type == Event::EVENT_CLOSED)
{
exit(0);
}
}
}
void ANGLETestBase::swapBuffers()
{
if (mEGLWindow->isGLInitialized())
{
mEGLWindow->swap();
}
}
void ANGLETestBase::setupQuadVertexBuffer(GLfloat positionAttribZ, GLfloat positionAttribXYScale)
{
if (mQuadVertexBuffer == 0)
{
glGenBuffers(1, &mQuadVertexBuffer);
}
auto quadVertices = GetQuadVertices();
for (angle::Vector3 &vertex : quadVertices)
{
vertex.x() *= positionAttribXYScale;
vertex.y() *= positionAttribXYScale;
vertex.z() = positionAttribZ;
}
glBindBuffer(GL_ARRAY_BUFFER, mQuadVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * 6, quadVertices.data(), GL_STATIC_DRAW);
}
void ANGLETestBase::setupIndexedQuadVertexBuffer(GLfloat positionAttribZ,
GLfloat positionAttribXYScale)
{
if (mQuadVertexBuffer == 0)
{
glGenBuffers(1, &mQuadVertexBuffer);
}
auto quadVertices = angle::kIndexedQuadVertices;
for (angle::Vector3 &vertex : quadVertices)
{
vertex.x() *= positionAttribXYScale;
vertex.y() *= positionAttribXYScale;
vertex.z() = positionAttribZ;
}
glBindBuffer(GL_ARRAY_BUFFER, mQuadVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * 4, quadVertices.data(), GL_STATIC_DRAW);
}
void ANGLETestBase::setupIndexedQuadIndexBuffer()
{
if (mQuadIndexBuffer == 0)
{
glGenBuffers(1, &mQuadIndexBuffer);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mQuadIndexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(angle::kIndexedQuadIndices),
angle::kIndexedQuadIndices.data(), GL_STATIC_DRAW);
}
// static
void ANGLETestBase::drawQuad(GLuint program,
const std::string &positionAttribName,
GLfloat positionAttribZ)
{
drawQuad(program, positionAttribName, positionAttribZ, 1.0f);
}
// static
void ANGLETestBase::drawQuad(GLuint program,
const std::string &positionAttribName,
GLfloat positionAttribZ,
GLfloat positionAttribXYScale)
{
drawQuad(program, positionAttribName, positionAttribZ, positionAttribXYScale, false);
}
void ANGLETestBase::drawQuad(GLuint program,
const std::string &positionAttribName,
GLfloat positionAttribZ,
GLfloat positionAttribXYScale,
bool useVertexBuffer)
{
drawQuad(program, positionAttribName, positionAttribZ, positionAttribXYScale, useVertexBuffer,
false, 0u);
}
void ANGLETestBase::drawQuadInstanced(GLuint program,
const std::string &positionAttribName,
GLfloat positionAttribZ,
GLfloat positionAttribXYScale,
bool useVertexBuffer,
GLuint numInstances)
{
drawQuad(program, positionAttribName, positionAttribZ, positionAttribXYScale, useVertexBuffer,
true, numInstances);
}
void ANGLETestBase::drawQuad(GLuint program,
const std::string &positionAttribName,
GLfloat positionAttribZ,
GLfloat positionAttribXYScale,
bool useVertexBuffer,
bool useInstancedDrawCalls,
GLuint numInstances)
{
GLint previousProgram = 0;
glGetIntegerv(GL_CURRENT_PROGRAM, &previousProgram);
if (previousProgram != static_cast<GLint>(program))
{
glUseProgram(program);
}
GLint previousBuffer = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &previousBuffer);
GLint positionLocation = glGetAttribLocation(program, positionAttribName.c_str());
std::array<angle::Vector3, 6> quadVertices;
if (useVertexBuffer)
{
setupQuadVertexBuffer(positionAttribZ, positionAttribXYScale);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, previousBuffer);
}
else
{
quadVertices = GetQuadVertices();
for (angle::Vector3 &vertex : quadVertices)
{
vertex.x() *= positionAttribXYScale;
vertex.y() *= positionAttribXYScale;
vertex.z() = positionAttribZ;
}
if (previousBuffer != 0)
{
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, quadVertices.data());
if (previousBuffer != 0)
{
glBindBuffer(GL_ARRAY_BUFFER, previousBuffer);
}
}
glEnableVertexAttribArray(positionLocation);
if (useInstancedDrawCalls)
{
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, numInstances);
}
else
{
glDrawArrays(GL_TRIANGLES, 0, 6);
}
glDisableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
if (previousProgram != static_cast<GLint>(program))
{
glUseProgram(previousProgram);
}
}
void ANGLETestBase::drawIndexedQuad(GLuint program,
const std::string &positionAttribName,
GLfloat positionAttribZ)
{
drawIndexedQuad(program, positionAttribName, positionAttribZ, 1.0f);
}
void ANGLETestBase::drawIndexedQuad(GLuint program,
const std::string &positionAttribName,
GLfloat positionAttribZ,
GLfloat positionAttribXYScale)
{
drawIndexedQuad(program, positionAttribName, positionAttribZ, positionAttribXYScale, false);
}
void ANGLETestBase::drawIndexedQuad(GLuint program,
const std::string &positionAttribName,
GLfloat positionAttribZ,
GLfloat positionAttribXYScale,
bool useIndexBuffer)
{
drawIndexedQuad(program, positionAttribName, positionAttribZ, positionAttribXYScale,
useIndexBuffer, false);
}
void ANGLETestBase::drawIndexedQuad(GLuint program,
const std::string &positionAttribName,
GLfloat positionAttribZ,
GLfloat positionAttribXYScale,
bool useIndexBuffer,
bool restrictedRange)
{
GLint positionLocation = glGetAttribLocation(program, positionAttribName.c_str());
GLint activeProgram = 0;
glGetIntegerv(GL_CURRENT_PROGRAM, &activeProgram);
if (static_cast<GLuint>(activeProgram) != program)
{
glUseProgram(program);
}
GLuint prevCoordBinding = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, reinterpret_cast<GLint *>(&prevCoordBinding));
setupIndexedQuadVertexBuffer(positionAttribZ, positionAttribXYScale);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(positionLocation);
glBindBuffer(GL_ARRAY_BUFFER, prevCoordBinding);
GLuint prevIndexBinding = 0;
const GLvoid *indices;
if (useIndexBuffer)
{
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING,
reinterpret_cast<GLint *>(&prevIndexBinding));
setupIndexedQuadIndexBuffer();
indices = 0;
}
else
{
indices = angle::kIndexedQuadIndices.data();
}
if (!restrictedRange)
{
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
}
else
{
glDrawRangeElements(GL_TRIANGLES, 0, 3, 6, GL_UNSIGNED_SHORT, indices);
}
if (useIndexBuffer)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prevIndexBinding);
}
glDisableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
if (static_cast<GLuint>(activeProgram) != program)
{
glUseProgram(static_cast<GLuint>(activeProgram));
}
}
GLuint ANGLETestBase::get2DTexturedQuadProgram()
{
if (m2DTexturedQuadProgram)
{
return m2DTexturedQuadProgram;
}
constexpr char kVS[] =
"attribute vec2 position;\n"
"varying mediump vec2 texCoord;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(position, 0, 1);\n"
" texCoord = position * 0.5 + vec2(0.5);\n"
"}\n";
constexpr char kFS[] =
"varying mediump vec2 texCoord;\n"
"uniform sampler2D tex;\n"
"void main()\n"
"{\n"
" gl_FragColor = texture2D(tex, texCoord);\n"
"}\n";
m2DTexturedQuadProgram = CompileProgram(kVS, kFS);
return m2DTexturedQuadProgram;
}
GLuint ANGLETestBase::get3DTexturedQuadProgram()
{
if (m3DTexturedQuadProgram)
{
return m3DTexturedQuadProgram;
}
constexpr char kVS[] = R"(#version 300 es
in vec2 position;
out vec2 texCoord;
void main()
{
gl_Position = vec4(position, 0, 1);
texCoord = position * 0.5 + vec2(0.5);
})";
constexpr char kFS[] = R"(#version 300 es
precision highp float;
in vec2 texCoord;
out vec4 my_FragColor;
uniform highp sampler3D tex;
uniform float u_layer;
void main()
{
my_FragColor = texture(tex, vec3(texCoord, u_layer));
})";
m3DTexturedQuadProgram = CompileProgram(kVS, kFS);
return m3DTexturedQuadProgram;
}
void ANGLETestBase::draw2DTexturedQuad(GLfloat positionAttribZ,
GLfloat positionAttribXYScale,
bool useVertexBuffer)
{
ASSERT_NE(0u, get2DTexturedQuadProgram());
drawQuad(get2DTexturedQuadProgram(), "position", positionAttribZ, positionAttribXYScale,
useVertexBuffer);
}
void ANGLETestBase::draw3DTexturedQuad(GLfloat positionAttribZ,
GLfloat positionAttribXYScale,
bool useVertexBuffer,
float layer)
{
GLuint program = get3DTexturedQuadProgram();
ASSERT_NE(0u, program);
GLint activeProgram = 0;
glGetIntegerv(GL_CURRENT_PROGRAM, &activeProgram);
if (static_cast<GLuint>(activeProgram) != program)
{
glUseProgram(program);
}
glUniform1f(glGetUniformLocation(program, "u_layer"), layer);
drawQuad(program, "position", positionAttribZ, positionAttribXYScale, useVertexBuffer);
if (static_cast<GLuint>(activeProgram) != program)
{
glUseProgram(static_cast<GLuint>(activeProgram));
}
}
void ANGLETestBase::checkD3D11SDKLayersMessages()
{
#if defined(ANGLE_PLATFORM_WINDOWS)
// On Windows D3D11, check ID3D11InfoQueue to see if any D3D11 SDK Layers messages
// were outputted by the test. We enable the Debug layers in Release tests as well.
if (mIgnoreD3D11SDKLayersWarnings ||
mEGLWindow->getPlatform().renderer != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE ||
mEGLWindow->getDisplay() == EGL_NO_DISPLAY)
{
return;
}
const char *extensionString =
static_cast<const char *>(eglQueryString(mEGLWindow->getDisplay(), EGL_EXTENSIONS));
if (!extensionString)
{
std::cout << "Error getting extension string from EGL Window." << std::endl;
return;
}
if (!strstr(extensionString, "EGL_EXT_device_query"))
{
return;
}
EGLAttrib device = 0;
EGLAttrib angleDevice = 0;
PFNEGLQUERYDISPLAYATTRIBEXTPROC queryDisplayAttribEXT;
PFNEGLQUERYDEVICEATTRIBEXTPROC queryDeviceAttribEXT;
queryDisplayAttribEXT = reinterpret_cast<PFNEGLQUERYDISPLAYATTRIBEXTPROC>(
eglGetProcAddress("eglQueryDisplayAttribEXT"));
queryDeviceAttribEXT = reinterpret_cast<PFNEGLQUERYDEVICEATTRIBEXTPROC>(
eglGetProcAddress("eglQueryDeviceAttribEXT"));
ASSERT_NE(nullptr, queryDisplayAttribEXT);
ASSERT_NE(nullptr, queryDeviceAttribEXT);
ASSERT_EGL_TRUE(queryDisplayAttribEXT(mEGLWindow->getDisplay(), EGL_DEVICE_EXT, &angleDevice));
ASSERT_EGL_TRUE(queryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice),
EGL_D3D11_DEVICE_ANGLE, &device));
ID3D11Device *d3d11Device = reinterpret_cast<ID3D11Device *>(device);
ID3D11InfoQueue *infoQueue = nullptr;
HRESULT hr =
d3d11Device->QueryInterface(__uuidof(infoQueue), reinterpret_cast<void **>(&infoQueue));
if (SUCCEEDED(hr))
{
UINT64 numStoredD3DDebugMessages =
infoQueue->GetNumStoredMessagesAllowedByRetrievalFilter();
if (numStoredD3DDebugMessages > 0)
{
for (UINT64 i = 0; i < numStoredD3DDebugMessages; i++)
{
SIZE_T messageLength = 0;
hr = infoQueue->GetMessage(i, nullptr, &messageLength);
if (SUCCEEDED(hr))
{
D3D11_MESSAGE *pMessage =
reinterpret_cast<D3D11_MESSAGE *>(malloc(messageLength));
infoQueue->GetMessage(i, pMessage, &messageLength);
std::cout << "Message " << i << ":"
<< " " << pMessage->pDescription << "\n";
free(pMessage);
}
}
FAIL() << numStoredD3DDebugMessages
<< " D3D11 SDK Layers message(s) detected! Test Failed.\n";
}
}
SafeRelease(infoQueue);
#endif // defined(ANGLE_PLATFORM_WINDOWS)
}
bool ANGLETestBase::extensionEnabled(const std::string &extName)
{
return CheckExtensionExists(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)),
extName);
}
bool ANGLETestBase::extensionRequestable(const std::string &extName)
{
return CheckExtensionExists(
reinterpret_cast<const char *>(glGetString(GL_REQUESTABLE_EXTENSIONS_ANGLE)), extName);
}
bool ANGLETestBase::ensureExtensionEnabled(const std::string &extName)
{
if (extensionEnabled("GL_ANGLE_request_extension") && extensionRequestable(extName))
{
glRequestExtensionANGLE(extName.c_str());
}
return extensionEnabled(extName);
}
bool ANGLETestBase::eglDisplayExtensionEnabled(EGLDisplay display, const std::string &extName)
{
return CheckExtensionExists(eglQueryString(display, EGL_EXTENSIONS), extName);
}
bool ANGLETestBase::eglClientExtensionEnabled(const std::string &extName)
{
return EGLWindow::ClientExtensionEnabled(extName);
}
bool ANGLETestBase::eglDeviceExtensionEnabled(EGLDeviceEXT device, const std::string &extName)
{
PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT =
reinterpret_cast<PFNEGLQUERYDEVICESTRINGEXTPROC>(
eglGetProcAddress("eglQueryDeviceStringEXT"));
return CheckExtensionExists(eglQueryDeviceStringEXT(device, EGL_EXTENSIONS), extName);
}
void ANGLETestBase::setWindowWidth(int width)
{
mWidth = width;
}
void ANGLETestBase::setWindowHeight(int height)
{
mHeight = height;
}
void ANGLETestBase::setConfigRedBits(int bits)
{
mEGLWindow->setConfigRedBits(bits);
}
void ANGLETestBase::setConfigGreenBits(int bits)
{
mEGLWindow->setConfigGreenBits(bits);
}
void ANGLETestBase::setConfigBlueBits(int bits)
{
mEGLWindow->setConfigBlueBits(bits);
}
void ANGLETestBase::setConfigAlphaBits(int bits)
{
mEGLWindow->setConfigAlphaBits(bits);
}
void ANGLETestBase::setConfigDepthBits(int bits)
{
mEGLWindow->setConfigDepthBits(bits);
}
void ANGLETestBase::setConfigStencilBits(int bits)
{
mEGLWindow->setConfigStencilBits(bits);
}
void ANGLETestBase::setConfigComponentType(EGLenum componentType)
{
mEGLWindow->setConfigComponentType(componentType);
}
void ANGLETestBase::setMultisampleEnabled(bool enabled)
{
mEGLWindow->setMultisample(enabled);
}
void ANGLETestBase::setSamples(EGLint samples)
{
mEGLWindow->setSamples(samples);
}
void ANGLETestBase::setDebugEnabled(bool enabled)
{
mEGLWindow->setDebugEnabled(enabled);
}
void ANGLETestBase::setNoErrorEnabled(bool enabled)
{
mEGLWindow->setNoErrorEnabled(enabled);
}
void ANGLETestBase::setWebGLCompatibilityEnabled(bool webglCompatibility)
{
mEGLWindow->setWebGLCompatibilityEnabled(webglCompatibility);
}
void ANGLETestBase::setExtensionsEnabled(bool extensionsEnabled)
{
mEGLWindow->setExtensionsEnabled(extensionsEnabled);
}
void ANGLETestBase::setRobustAccess(bool enabled)
{
mEGLWindow->setRobustAccess(enabled);
}
void ANGLETestBase::setBindGeneratesResource(bool bindGeneratesResource)
{
mEGLWindow->setBindGeneratesResource(bindGeneratesResource);
}
void ANGLETestBase::setDebugLayersEnabled(bool enabled)
{
mEGLWindow->setDebugLayersEnabled(enabled);
}
void ANGLETestBase::setClientArraysEnabled(bool enabled)
{
mEGLWindow->setClientArraysEnabled(enabled);
}
void ANGLETestBase::setRobustResourceInit(bool enabled)
{
mEGLWindow->setRobustResourceInit(enabled);
}
void ANGLETestBase::setContextProgramCacheEnabled(bool enabled)
{
mEGLWindow->setContextProgramCacheEnabled(enabled);
}
void ANGLETestBase::setContextVirtualization(bool enabled)
{
mEGLWindow->setContextVirtualization(enabled);
}
void ANGLETestBase::setDeferContextInit(bool enabled)
{
mDeferContextInit = enabled;
}
int ANGLETestBase::getClientMajorVersion() const
{
return mEGLWindow->getClientMajorVersion();
}
int ANGLETestBase::getClientMinorVersion() const
{
return mEGLWindow->getClientMinorVersion();
}
EGLWindow *ANGLETestBase::getEGLWindow() const
{
return mEGLWindow;
}
int ANGLETestBase::getWindowWidth() const
{
return mWidth;
}
int ANGLETestBase::getWindowHeight() const
{
return mHeight;
}
bool ANGLETestBase::isMultisampleEnabled() const
{
return mEGLWindow->isMultisample();
}
bool ANGLETestBase::destroyEGLContext()
{
mEGLWindow->destroyGL();
return true;
}
// static
bool ANGLETestBase::InitTestWindow()
{
mOSWindow = CreateOSWindow();
if (!mOSWindow->initialize("ANGLE_TEST", 128, 128))
{
return false;
}
mOSWindow->setVisible(true);
return true;
}
// static
bool ANGLETestBase::DestroyTestWindow()
{
if (mOSWindow)
{
mOSWindow->destroy();
delete mOSWindow;
mOSWindow = nullptr;
}
return true;
}
void ANGLETestBase::SetWindowVisible(bool isVisible)
{
mOSWindow->setVisible(isVisible);
}
ANGLETest::ANGLETest() : ANGLETestBase(GetParam()) {}
void ANGLETest::SetUp()
{
ANGLETestBase::ANGLETestSetUp();
}
void ANGLETest::TearDown()
{
ANGLETestBase::ANGLETestTearDown();
}
bool IsIntel()
{
std::string rendererString(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
return (rendererString.find("Intel") != std::string::npos);
}
bool IsAdreno()
{
std::string rendererString(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
return (rendererString.find("Adreno") != std::string::npos);
}
bool IsAMD()
{
std::string rendererString(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
return (rendererString.find("AMD") != std::string::npos) ||
(rendererString.find("ATI") != std::string::npos) ||
(rendererString.find("Radeon") != std::string::npos);
}
bool IsNVIDIA()
{
std::string rendererString(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
return (rendererString.find("NVIDIA") != std::string::npos);
}
bool IsD3D11()
{
std::string rendererString(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
return (rendererString.find("Direct3D11 vs_5_0") != std::string::npos);
}
bool IsD3D11_FL93()
{
std::string rendererString(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
return (rendererString.find("Direct3D11 vs_4_0_") != std::string::npos);
}
bool IsD3D9()
{
std::string rendererString(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
return (rendererString.find("Direct3D9") != std::string::npos);
}
bool IsD3DSM3()
{
return IsD3D9() || IsD3D11_FL93();
}
bool IsDesktopOpenGL()
{
return IsOpenGL() && !IsOpenGLES();
}
bool IsOpenGLES()
{
std::string rendererString(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
return (rendererString.find("OpenGL ES") != std::string::npos);
}
bool IsOpenGL()
{
std::string rendererString(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
return (rendererString.find("OpenGL") != std::string::npos);
}
bool IsNULL()
{
std::string rendererString(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
return (rendererString.find("NULL") != std::string::npos);
}
bool IsAndroid()
{
#if defined(ANGLE_PLATFORM_ANDROID)
return true;
#else
return false;
#endif
}
bool IsVulkan()
{
const char *renderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
std::string rendererString(renderer);
return (rendererString.find("Vulkan") != std::string::npos);
}
bool IsOzone()
{
#if defined(USE_OZONE)
return true;
#else
return false;
#endif
}
bool IsLinux()
{
#if defined(ANGLE_PLATFORM_LINUX)
return true;
#else
return false;
#endif
}
bool IsOSX()
{
#if defined(ANGLE_PLATFORM_APPLE)
return true;
#else
return false;
#endif
}
bool IsWindows()
{
#if defined(ANGLE_PLATFORM_WINDOWS)
return true;
#else
return false;
#endif
}
bool IsDebug()
{
#if !defined(NDEBUG)
return true;
#else
return false;
#endif
}
bool IsRelease()
{
return !IsDebug();
}
EGLint ANGLETestBase::getPlatformRenderer() const
{
assert(mEGLWindow);
return mEGLWindow->getPlatform().renderer;
}
void ANGLETestBase::ignoreD3D11SDKLayersWarnings()
{
// Some tests may need to disable the D3D11 SDK Layers Warnings checks
mIgnoreD3D11SDKLayersWarnings = true;
}
ANGLETestBase::ScopedIgnorePlatformMessages::ScopedIgnorePlatformMessages(ANGLETestBase *test)
: mTest(test)
{
mTest->mPlatformContext.ignoreMessages = true;
}
ANGLETestBase::ScopedIgnorePlatformMessages::~ScopedIgnorePlatformMessages()
{
mTest->mPlatformContext.ignoreMessages = false;
}
OSWindow *ANGLETestBase::mOSWindow = nullptr;
Optional<EGLint> ANGLETestBase::mLastRendererType;
void ANGLETestEnvironment::SetUp()
{
if (!ANGLETestBase::InitTestWindow())
{
FAIL() << "Failed to create ANGLE test window.";
}
}
void ANGLETestEnvironment::TearDown()
{
ANGLETestBase::DestroyTestWindow();
}
void ANGLEProcessTestArgs(int *argc, char *argv[])
{
testing::AddGlobalTestEnvironment(new ANGLETestEnvironment());
}