blob: 4c43ab8bdac4459c3c51dc7146b2e5d8fdde2f0a [file] [log] [blame]
//
// Copyright 2016 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.
//
// RobustClientMemoryTest.cpp : Tests of the GL_ANGLE_robust_client_memory extension.
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
namespace angle
{
constexpr GLsizei kWindowSize = 128;
class RobustClientMemoryTest : public ANGLETest
{
protected:
RobustClientMemoryTest()
{
setWindowWidth(kWindowSize);
setWindowHeight(kWindowSize);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
bool extensionsPresent() const
{
if (!IsGLExtensionEnabled("GL_ANGLE_robust_client_memory"))
{
std::cout << "Test skipped because GL_ANGLE_robust_client_memory is not available.";
return false;
}
return true;
}
};
// Test basic usage and validation of glGetIntegervRobustANGLE
TEST_P(RobustClientMemoryTest, GetInteger)
{
if (!extensionsPresent())
{
return;
}
// Verify that the robust and regular entry points return the same values
GLint resultRobust;
GLsizei length;
glGetIntegervRobustANGLE(GL_MAX_VERTEX_ATTRIBS, 1, &length, &resultRobust);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(1, length);
GLint resultRegular;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &resultRegular);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(resultRegular, resultRobust);
// Query a dynamic value
GLint numCompressedFormats;
glGetIntegervRobustANGLE(GL_NUM_COMPRESSED_TEXTURE_FORMATS, 1, &length, &numCompressedFormats);
ASSERT_GL_NO_ERROR();
EXPECT_EQ(1, length);
if (numCompressedFormats > 0)
{
std::vector<GLint> resultBuf(numCompressedFormats * 2, 0);
// Test when the bufSize is too low
glGetIntegervRobustANGLE(GL_COMPRESSED_TEXTURE_FORMATS, numCompressedFormats - 1, &length,
resultBuf.data());
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
EXPECT_TRUE(std::all_of(resultBuf.begin(), resultBuf.end(),
[](GLint value) { return value == 0; }));
// Make sure the GL doesn't touch the end of the buffer
glGetIntegervRobustANGLE(GL_COMPRESSED_TEXTURE_FORMATS,
static_cast<GLsizei>(resultBuf.size()), &length, resultBuf.data());
EXPECT_GL_NO_ERROR();
EXPECT_EQ(numCompressedFormats, length);
EXPECT_TRUE(std::none_of(resultBuf.begin(), resultBuf.begin() + length,
[](GLint value) { return value == 0; }));
EXPECT_TRUE(std::all_of(resultBuf.begin() + length, resultBuf.end(),
[](GLint value) { return value == 0; }));
}
// Test with null length
glGetIntegervRobustANGLE(GL_MAX_VARYING_VECTORS, 1, nullptr, &resultRobust);
EXPECT_GL_NO_ERROR();
glGetIntegervRobustANGLE(GL_MAX_VIEWPORT_DIMS, 1, nullptr, &resultRobust);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
GLint maxViewportDims[2];
glGetIntegervRobustANGLE(GL_MAX_VIEWPORT_DIMS, 2, nullptr, maxViewportDims);
EXPECT_GL_NO_ERROR();
}
// Test basic usage and validation of glTexImage2DRobustANGLE and glTexSubImage2DRobustANGLE
TEST_P(RobustClientMemoryTest, TexImage2D)
{
if (!extensionsPresent())
{
return;
}
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex.get());
GLsizei dataDimension = 1024;
std::vector<GLubyte> rgbaData(dataDimension * dataDimension * 4);
// Test the regular case
glTexImage2DRobustANGLE(GL_TEXTURE_2D, 0, GL_RGBA, dataDimension, dataDimension, 0, GL_RGBA,
GL_UNSIGNED_BYTE, static_cast<GLsizei>(rgbaData.size()),
rgbaData.data());
EXPECT_GL_NO_ERROR();
glTexSubImage2DRobustANGLE(GL_TEXTURE_2D, 0, 0, 0, dataDimension, dataDimension, GL_RGBA,
GL_UNSIGNED_BYTE, static_cast<GLsizei>(rgbaData.size()),
rgbaData.data());
EXPECT_GL_NO_ERROR();
// Test with a data size that is too small
glTexImage2DRobustANGLE(GL_TEXTURE_2D, 0, GL_RGBA, dataDimension, dataDimension, 0, GL_RGBA,
GL_UNSIGNED_BYTE, static_cast<GLsizei>(rgbaData.size()) / 2,
rgbaData.data());
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
glTexSubImage2DRobustANGLE(GL_TEXTURE_2D, 0, 0, 0, dataDimension, dataDimension, GL_RGBA,
GL_UNSIGNED_BYTE, static_cast<GLsizei>(rgbaData.size()) / 2,
rgbaData.data());
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
if (getClientMajorVersion() >= 3)
{
// Set an unpack parameter that would cause the driver to read past the end of the buffer
glPixelStorei(GL_UNPACK_ROW_LENGTH, dataDimension + 1);
glTexImage2DRobustANGLE(GL_TEXTURE_2D, 0, GL_RGBA, dataDimension, dataDimension, 0, GL_RGBA,
GL_UNSIGNED_BYTE, static_cast<GLsizei>(rgbaData.size()),
rgbaData.data());
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
}
// Test basic usage and validation of glReadPixelsRobustANGLE
TEST_P(RobustClientMemoryTest, ReadPixels)
{
if (!extensionsPresent())
{
return;
}
// TODO(ynovikov): Looks like a driver bug on Intel HD 530 http://anglebug.com/1877
ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsDesktopOpenGL());
GLsizei dataDimension = 16;
std::vector<GLubyte> rgbaData(dataDimension * dataDimension * 4);
// Test the regular case
GLsizei length = 0;
GLsizei width = 0;
GLsizei height = 0;
glReadPixelsRobustANGLE(0, 0, dataDimension, dataDimension, GL_RGBA, GL_UNSIGNED_BYTE,
static_cast<GLsizei>(rgbaData.size()), &length, &width, &height,
rgbaData.data());
EXPECT_GL_NO_ERROR();
EXPECT_EQ(static_cast<GLsizei>(rgbaData.size()), length);
EXPECT_EQ(dataDimension, width);
EXPECT_EQ(dataDimension, height);
// Test a case that would be partially clipped
glReadPixelsRobustANGLE(-1, kWindowSize - dataDimension + 3, dataDimension, dataDimension,
GL_RGBA, GL_UNSIGNED_BYTE, static_cast<GLsizei>(rgbaData.size()),
&length, &width, &height, rgbaData.data());
EXPECT_GL_NO_ERROR();
EXPECT_EQ(static_cast<GLsizei>(rgbaData.size()), length);
EXPECT_EQ(dataDimension - 1, width);
EXPECT_EQ(dataDimension - 3, height);
// Test with a data size that is too small
glReadPixelsRobustANGLE(0, 0, dataDimension, dataDimension, GL_RGBA, GL_UNSIGNED_BYTE,
static_cast<GLsizei>(rgbaData.size()) - 1, &length, nullptr, nullptr,
rgbaData.data());
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
if (getClientMajorVersion() >= 3)
{
// Set a pack parameter that would cause the driver to write past the end of the buffer
glPixelStorei(GL_PACK_ROW_LENGTH, dataDimension + 1);
glReadPixelsRobustANGLE(0, 0, dataDimension, dataDimension, GL_RGBA, GL_UNSIGNED_BYTE,
static_cast<GLsizei>(rgbaData.size()), &length, nullptr, nullptr,
rgbaData.data());
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST(RobustClientMemoryTest,
ES2_D3D9(),
ES2_D3D11(),
ES3_D3D11(),
ES2_OPENGL(),
ES3_OPENGL(),
ES2_OPENGLES(),
ES3_OPENGLES(),
ES2_VULKAN());
} // namespace angle