| // Copyright (C) 2018 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "GLSnapshotTesting.h" |
| #include "OpenGLTestContext.h" |
| |
| #include <gtest/gtest.h> |
| #include <array> |
| |
| namespace gfxstream { |
| namespace gl { |
| namespace { |
| |
| struct GlStencilFunc { |
| GLenum func; |
| GLint ref; |
| GLuint mask; |
| }; |
| |
| struct GlStencilOp { |
| GLenum sfail; |
| GLenum dpfail; |
| GLenum dppass; |
| }; |
| |
| struct GlBlendFunc { |
| GLenum srcRGB; |
| GLenum dstRGB; |
| GLenum srcAlpha; |
| GLenum dstAlpha; |
| }; |
| |
| struct GlWriteMask { |
| GLboolean colorMaskR; |
| GLboolean colorMaskG; |
| GLboolean colorMaskB; |
| GLboolean colorMaskA; |
| }; |
| |
| static const int kTestMaxDrawBuffers = 8; |
| |
| typedef std::array<GlWriteMask, kTestMaxDrawBuffers> GlWriteMaskArray; |
| typedef std::array<GlBlendFunc, kTestMaxDrawBuffers> GlBlendFuncArray; |
| |
| static constexpr GlWriteMaskArray kGLES2TestWriteMaski {{ |
| {GL_TRUE, GL_FALSE, GL_TRUE, GL_TRUE}, |
| {GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE}, |
| {GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE}, |
| {GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE}, |
| {GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE}, |
| {GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE}, |
| {GL_TRUE, GL_TRUE, GL_FALSE, GL_FALSE}, |
| {GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE} |
| }}; |
| |
| static constexpr GlBlendFuncArray kGLES2TestBlendFunci {{ |
| {GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR}, |
| {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA}, |
| {GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR, GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA}, |
| {GL_SRC_ALPHA_SATURATE, GL_ONE, GL_SRC_ALPHA_SATURATE, GL_ONE}, |
| {GL_ONE_MINUS_SRC_COLOR, GL_SRC_COLOR, GL_ONE_MINUS_DST_COLOR, GL_DST_COLOR}, |
| {GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_SRC_COLOR, GL_SRC_COLOR}, |
| {GL_ONE_MINUS_CONSTANT_COLOR, GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_ALPHA, GL_CONSTANT_ALPHA}, |
| {GL_ONE, GL_SRC_ALPHA_SATURATE, GL_ONE, GL_SRC_ALPHA_SATURATE}, |
| }}; |
| |
| // Scissor box settings to attempt |
| static const std::vector<GLint> kGLES2TestScissorBox = {2, 3, 10, 20}; |
| |
| // Default stencil operation modes |
| static const GlStencilOp kGLES2DefaultStencilOp = {GL_KEEP, GL_KEEP, GL_KEEP}; |
| |
| // Stencil reference value to attempt |
| static const GLint kGLES2TestStencilRef = 1; |
| |
| // Stencil mask values to attempt |
| static const GLuint kGLES2TestStencilMasks[] = {0, 1, 0x1000000, 0x7FFFFFFF}; |
| |
| // Blend function settings to attempt |
| static const GlBlendFunc kGLES2TestBlendFuncs[] = { |
| {GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_DST_COLOR, |
| GL_ONE_MINUS_DST_COLOR}, |
| {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, |
| GL_ONE_MINUS_DST_ALPHA}, |
| {GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR, GL_CONSTANT_ALPHA, |
| GL_ONE_MINUS_CONSTANT_ALPHA}, |
| {GL_SRC_ALPHA_SATURATE, GL_ONE, GL_SRC_ALPHA_SATURATE, GL_ONE}}; |
| |
| class SnapshotGlScissorBoxTest |
| : public SnapshotSetValueTest<std::vector<GLint>>, |
| public ::testing::WithParamInterface<std::vector<GLint>> { |
| void stateCheck(std::vector<GLint> expected) override { |
| EXPECT_TRUE(compareGlobalGlIntv(gl, GL_SCISSOR_BOX, expected)); |
| } |
| void stateChange() override { |
| gl->glScissor(GetParam()[0], GetParam()[1], GetParam()[2], |
| GetParam()[3]); |
| } |
| }; |
| |
| TEST_P(SnapshotGlScissorBoxTest, SetScissorBox) { |
| // different drivers act differently; get the default scissorbox |
| std::vector<GLint> defaultBox; |
| defaultBox.resize(4); |
| gl->glGetIntegerv(GL_SCISSOR_BOX, &defaultBox[0]); |
| EXPECT_EQ(GL_NO_ERROR, gl->glGetError()); |
| |
| setExpectedValues(defaultBox, GetParam()); |
| doCheckedSnapshot(); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(GLES2SnapshotPixelOps, |
| SnapshotGlScissorBoxTest, |
| ::testing::Values(kGLES2TestScissorBox)); |
| |
| // Tests preservation of stencil test conditional state, set by glStencilFunc. |
| class SnapshotGlStencilConditionsTest |
| : public SnapshotSetValueTest<GlStencilFunc> { |
| void stateCheck(GlStencilFunc expected) override { |
| EXPECT_TRUE(compareGlobalGlInt(gl, GL_STENCIL_FUNC, expected.func)); |
| EXPECT_TRUE(compareGlobalGlInt(gl, GL_STENCIL_REF, expected.ref)); |
| EXPECT_TRUE( |
| compareGlobalGlInt(gl, GL_STENCIL_VALUE_MASK, expected.mask)); |
| EXPECT_TRUE( |
| compareGlobalGlInt(gl, GL_STENCIL_BACK_FUNC, expected.func)); |
| EXPECT_TRUE(compareGlobalGlInt(gl, GL_STENCIL_BACK_REF, expected.ref)); |
| EXPECT_TRUE(compareGlobalGlInt(gl, GL_STENCIL_BACK_VALUE_MASK, |
| expected.mask)); |
| } |
| void stateChange() override { |
| GlStencilFunc sFunc = *m_changed_value; |
| gl->glStencilFunc(sFunc.func, sFunc.ref, sFunc.mask); |
| } |
| }; |
| |
| class SnapshotGlStencilFuncTest : public SnapshotGlStencilConditionsTest, |
| public ::testing::WithParamInterface<GLenum> { |
| }; |
| |
| class SnapshotGlStencilMaskTest : public SnapshotGlStencilConditionsTest, |
| public ::testing::WithParamInterface<GLuint> { |
| }; |
| |
| TEST_P(SnapshotGlStencilFuncTest, SetStencilFunc) { |
| // different drivers act differently; get the default mask |
| GLint defaultStencilMask; |
| gl->glGetIntegerv(GL_STENCIL_VALUE_MASK, &defaultStencilMask); |
| EXPECT_EQ(GL_NO_ERROR, gl->glGetError()); |
| |
| GlStencilFunc defaultStencilFunc = {GL_ALWAYS, 0, |
| (GLuint)defaultStencilMask}; |
| GlStencilFunc testStencilFunc = {GetParam(), kGLES2TestStencilRef, 0}; |
| setExpectedValues(defaultStencilFunc, testStencilFunc); |
| doCheckedSnapshot(); |
| } |
| |
| TEST_P(SnapshotGlStencilMaskTest, SetStencilMask) { |
| // different drivers act differently; get the default mask |
| GLint defaultStencilMask; |
| gl->glGetIntegerv(GL_STENCIL_VALUE_MASK, &defaultStencilMask); |
| EXPECT_EQ(GL_NO_ERROR, gl->glGetError()); |
| |
| GlStencilFunc defaultStencilFunc = {GL_ALWAYS, 0, |
| (GLuint)defaultStencilMask}; |
| GlStencilFunc testStencilFunc = {GL_ALWAYS, kGLES2TestStencilRef, |
| GetParam()}; |
| setExpectedValues(defaultStencilFunc, testStencilFunc); |
| doCheckedSnapshot(); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(GLES2SnapshotPixelOps, |
| SnapshotGlStencilFuncTest, |
| ::testing::ValuesIn(kGLES2StencilFuncs)); |
| |
| INSTANTIATE_TEST_SUITE_P(GLES2SnapshotPixelOps, |
| SnapshotGlStencilMaskTest, |
| ::testing::ValuesIn(kGLES2TestStencilMasks)); |
| |
| class SnapshotGlStencilConsequenceTest |
| : public SnapshotSetValueTest<GlStencilOp> { |
| void stateCheck(GlStencilOp expected) override { |
| EXPECT_TRUE(compareGlobalGlInt(gl, GL_STENCIL_FAIL, expected.sfail)); |
| EXPECT_TRUE(compareGlobalGlInt(gl, GL_STENCIL_PASS_DEPTH_FAIL, |
| expected.dpfail)); |
| EXPECT_TRUE(compareGlobalGlInt(gl, GL_STENCIL_PASS_DEPTH_PASS, |
| expected.dppass)); |
| EXPECT_TRUE( |
| compareGlobalGlInt(gl, GL_STENCIL_BACK_FAIL, expected.sfail)); |
| EXPECT_TRUE(compareGlobalGlInt(gl, GL_STENCIL_BACK_PASS_DEPTH_FAIL, |
| expected.dpfail)); |
| EXPECT_TRUE(compareGlobalGlInt(gl, GL_STENCIL_BACK_PASS_DEPTH_PASS, |
| expected.dppass)); |
| } |
| void stateChange() override { |
| GlStencilOp sOp = *m_changed_value; |
| gl->glStencilOp(sOp.sfail, sOp.dpfail, sOp.dppass); |
| } |
| }; |
| |
| class SnapshotGlStencilFailTest : public SnapshotGlStencilConsequenceTest, |
| public ::testing::WithParamInterface<GLenum> { |
| }; |
| |
| class SnapshotGlStencilDepthFailTest |
| : public SnapshotGlStencilConsequenceTest, |
| public ::testing::WithParamInterface<GLenum> {}; |
| |
| class SnapshotGlStencilDepthPassTest |
| : public SnapshotGlStencilConsequenceTest, |
| public ::testing::WithParamInterface<GLenum> {}; |
| |
| TEST_P(SnapshotGlStencilFailTest, SetStencilOps) { |
| GlStencilOp testStencilOp = {GetParam(), GL_KEEP, GL_KEEP}; |
| setExpectedValues(kGLES2DefaultStencilOp, testStencilOp); |
| doCheckedSnapshot(); |
| } |
| |
| TEST_P(SnapshotGlStencilDepthFailTest, SetStencilOps) { |
| GlStencilOp testStencilOp = {GL_KEEP, GetParam(), GL_KEEP}; |
| setExpectedValues(kGLES2DefaultStencilOp, testStencilOp); |
| doCheckedSnapshot(); |
| } |
| |
| TEST_P(SnapshotGlStencilDepthPassTest, SetStencilOps) { |
| GlStencilOp testStencilOp = {GL_KEEP, GL_KEEP, GetParam()}; |
| setExpectedValues(kGLES2DefaultStencilOp, testStencilOp); |
| doCheckedSnapshot(); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(GLES2SnapshotPixelOps, |
| SnapshotGlStencilFailTest, |
| ::testing::ValuesIn(kGLES2StencilOps)); |
| |
| INSTANTIATE_TEST_SUITE_P(GLES2SnapshotPixelOps, |
| SnapshotGlStencilDepthFailTest, |
| ::testing::ValuesIn(kGLES2StencilOps)); |
| |
| INSTANTIATE_TEST_SUITE_P(GLES2SnapshotPixelOps, |
| SnapshotGlStencilDepthPassTest, |
| ::testing::ValuesIn(kGLES2StencilOps)); |
| |
| class SnapshotGlDepthFuncTest : public SnapshotSetValueTest<GLenum>, |
| public ::testing::WithParamInterface<GLenum> { |
| void stateCheck(GLenum expected) override { |
| EXPECT_TRUE(compareGlobalGlInt(gl, GL_DEPTH_FUNC, expected)); |
| } |
| void stateChange() override { gl->glDepthFunc(*m_changed_value); } |
| }; |
| |
| TEST_P(SnapshotGlDepthFuncTest, SetDepthFunc) { |
| setExpectedValues(GL_LESS, GetParam()); |
| doCheckedSnapshot(); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(GLES2SnapshotPixelOps, |
| SnapshotGlDepthFuncTest, |
| ::testing::ValuesIn(kGLES2StencilFuncs)); |
| |
| class SnapshotGlBlendEquationTest |
| : public SnapshotSetValueTest<GLenum>, |
| public ::testing::WithParamInterface<GLenum> { |
| void stateCheck(GLenum expected) override { |
| EXPECT_TRUE(compareGlobalGlInt(gl, GL_BLEND_EQUATION_RGB, expected)); |
| EXPECT_TRUE(compareGlobalGlInt(gl, GL_BLEND_EQUATION_ALPHA, expected)); |
| } |
| void stateChange() override { gl->glBlendEquation(*m_changed_value); } |
| }; |
| |
| TEST_P(SnapshotGlBlendEquationTest, SetBlendEquation) { |
| setExpectedValues(GL_FUNC_ADD, GetParam()); |
| doCheckedSnapshot(); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(GLES2SnapshotPixelOps, |
| SnapshotGlBlendEquationTest, |
| ::testing::ValuesIn(kGLES2BlendEquations)); |
| |
| class SnapshotGlBlendFuncTest |
| : public SnapshotSetValueTest<GlBlendFunc>, |
| public ::testing::WithParamInterface<GlBlendFunc> { |
| void stateCheck(GlBlendFunc expected) { |
| EXPECT_TRUE(compareGlobalGlInt(gl, GL_BLEND_SRC_RGB, expected.srcRGB)); |
| EXPECT_TRUE(compareGlobalGlInt(gl, GL_BLEND_DST_RGB, expected.dstRGB)); |
| EXPECT_TRUE( |
| compareGlobalGlInt(gl, GL_BLEND_SRC_ALPHA, expected.srcAlpha)); |
| EXPECT_TRUE( |
| compareGlobalGlInt(gl, GL_BLEND_DST_ALPHA, expected.dstAlpha)); |
| } |
| void stateChange() { |
| GlBlendFunc target = *m_changed_value; |
| gl->glBlendFuncSeparate(target.srcRGB, target.dstRGB, target.srcAlpha, |
| target.dstAlpha); |
| } |
| }; |
| |
| TEST_P(SnapshotGlBlendFuncTest, SetBlendFunc) { |
| GlBlendFunc defaultBlendFunc = {.srcRGB = GL_ONE, |
| .dstRGB = GL_ZERO, |
| .srcAlpha = GL_ONE, |
| .dstAlpha = GL_ZERO}; |
| setExpectedValues(defaultBlendFunc, GetParam()); |
| doCheckedSnapshot(); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(GLES2SnapshotPixelOps, |
| SnapshotGlBlendFuncTest, |
| ::testing::ValuesIn(kGLES2TestBlendFuncs)); |
| |
| class SnapshotGlWriteMaskiTest |
| : public SnapshotSetValueTest<GlWriteMaskArray>, |
| public ::testing::WithParamInterface<GlWriteMaskArray> { |
| |
| void stateCheck(GlWriteMaskArray expected) { |
| for(int i = 0 ; i < m_maxDrawBuffers ; ++i ) { |
| std::vector<GLboolean> res{expected[i].colorMaskR, expected[i].colorMaskG, expected[i].colorMaskB, expected[i].colorMaskA}; |
| EXPECT_TRUE(compareGlobalGlBooleanv_i(gl, GL_COLOR_WRITEMASK, i, res, 4)); |
| } |
| } |
| |
| void stateChange() { |
| auto& writeMasks = *m_changed_value; |
| for(int i = 0 ; i < m_maxDrawBuffers ; ++i) |
| gl->glColorMaskiEXT(i, |
| writeMasks[i].colorMaskR, |
| writeMasks[i].colorMaskG, |
| writeMasks[i].colorMaskB, |
| writeMasks[i].colorMaskA); |
| } |
| |
| protected: |
| GLint m_maxDrawBuffers = 1; |
| }; |
| |
| TEST_P(SnapshotGlWriteMaskiTest, ColorMaski) { |
| const std::string ext((const char*)gl->glGetString(GL_EXTENSIONS)); |
| EMUGL_SKIP_TEST_IF(ext.find("GL_EXT_draw_buffers_indexed") == std::string::npos); |
| gl->glGetIntegerv(GL_MAX_DRAW_BUFFERS, &m_maxDrawBuffers); |
| |
| const GlWriteMaskArray defaultWriteMask { { |
| {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE}, |
| {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE}, |
| {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE}, |
| {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE}, |
| {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE}, |
| {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE}, |
| {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE}, |
| {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE}, |
| } }; |
| setExpectedValues(defaultWriteMask, GetParam()); |
| doCheckedSnapshot(); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(GLES2SnapshotPixelOps, SnapshotGlWriteMaskiTest, |
| ::testing::Values(kGLES2TestWriteMaski)); |
| |
| // test glBlendFunci load and restore |
| class SnapshotGlBlendFunciTest |
| : public SnapshotSetValueTest<GlBlendFuncArray>, |
| public ::testing::WithParamInterface<GlBlendFuncArray> { |
| |
| void stateCheck(GlBlendFuncArray expected) { |
| for(int i = 0 ; i < m_maxDrawBuffers ; ++i ) { |
| EXPECT_TRUE(compareGlobalGlInt_i(gl, GL_BLEND_SRC_RGB, i, expected[i].srcRGB)); |
| EXPECT_TRUE(compareGlobalGlInt_i(gl, GL_BLEND_DST_RGB, i, expected[i].dstRGB)); |
| EXPECT_TRUE(compareGlobalGlInt_i(gl, GL_BLEND_SRC_ALPHA, i, expected[i].srcAlpha)); |
| EXPECT_TRUE(compareGlobalGlInt_i(gl, GL_BLEND_DST_ALPHA, i, expected[i].dstAlpha)); |
| } |
| } |
| |
| void stateChange() { |
| auto& blendFuncs = *m_changed_value; |
| for(int i = 0 ; i < m_maxDrawBuffers ; ++i) { |
| gl->glBlendFuncSeparateiEXT(i, blendFuncs[i].srcRGB, blendFuncs[i].dstRGB, blendFuncs[i].srcAlpha, |
| blendFuncs[i].dstAlpha); |
| } |
| } |
| |
| protected: |
| GLint m_maxDrawBuffers = 1; |
| }; |
| |
| TEST_P(SnapshotGlBlendFunciTest, BlendFunci) { |
| const std::string ext((const char*)gl->glGetString(GL_EXTENSIONS)); |
| EMUGL_SKIP_TEST_IF(ext.find("GL_EXT_draw_buffers_indexed") == std::string::npos); |
| gl->glGetIntegerv(GL_MAX_DRAW_BUFFERS, &m_maxDrawBuffers); |
| |
| const GlBlendFuncArray defaultBlendFunc { { |
| {GL_ONE, GL_ZERO, GL_ONE, GL_ZERO}, |
| {GL_ONE, GL_ZERO, GL_ONE, GL_ZERO}, |
| {GL_ONE, GL_ZERO, GL_ONE, GL_ZERO}, |
| {GL_ONE, GL_ZERO, GL_ONE, GL_ZERO}, |
| {GL_ONE, GL_ZERO, GL_ONE, GL_ZERO}, |
| {GL_ONE, GL_ZERO, GL_ONE, GL_ZERO}, |
| {GL_ONE, GL_ZERO, GL_ONE, GL_ZERO}, |
| {GL_ONE, GL_ZERO, GL_ONE, GL_ZERO}, |
| } }; |
| setExpectedValues(defaultBlendFunc, GetParam()); |
| doCheckedSnapshot(); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(GLES2SnapshotPixelOps, SnapshotGlBlendFunciTest, |
| ::testing::Values(kGLES2TestBlendFunci)); |
| |
| } // namespace |
| } // namespace gl |
| } // namespace gfxstream |