| // | |
| // 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_ES2_AND_ES3(RobustClientMemoryTest); | |
| } // namespace angle |