diff options
Diffstat (limited to 'gfx/angle/src/tests/gl_tests/FramebufferMixedSamplesTest.cpp')
-rwxr-xr-x | gfx/angle/src/tests/gl_tests/FramebufferMixedSamplesTest.cpp | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/gfx/angle/src/tests/gl_tests/FramebufferMixedSamplesTest.cpp b/gfx/angle/src/tests/gl_tests/FramebufferMixedSamplesTest.cpp new file mode 100755 index 000000000..5baf9303a --- /dev/null +++ b/gfx/angle/src/tests/gl_tests/FramebufferMixedSamplesTest.cpp @@ -0,0 +1,291 @@ +// +// 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. +// +// CHROMIUMFramebufferMixedSamplesTest +// Test CHROMIUM subset of NV_framebuffer_mixed_samples. +// This extension allows rendering to a framebuffer that has different +// sample counts for different render buffers (stencil, depth, color) + +#include "test_utils/ANGLETest.h" +#include "shader_utils.h" + +using namespace angle; + +namespace +{ + +const GLuint kWidth = 100; +const GLuint kHeight = 100; + +class CHROMIUMFramebufferMixedSamplesTest : public ANGLETest +{ + protected: + enum SetupFBOType + { + MixedSampleFBO, // 1 color sample, N stencil samples. + SingleSampleFBO, // 1 color sample, 1 stencil sample. + }; + + bool isApplicable() const + { + return extensionEnabled("GL_CHROMIUM_framebuffer_mixed_samples") && + extensionEnabled("GL_OES_rgb8_rgba8"); + } + + void SetUp() override + { + ANGLETest::SetUp(); + + // clang-format off + static const char* kVertexShaderSource = + "attribute mediump vec4 position;\n" + "void main() {\n" + " gl_Position = position;\n" + "}\n"; + + static const char* kFragmentShaderSource = + "uniform mediump vec4 color;\n" + "void main() {\n" + " gl_FragColor = color;\n" + "}\n"; + + // clang-format on + mProgram = CompileProgram(kVertexShaderSource, kFragmentShaderSource); + + GLuint position_loc = glGetAttribLocation(mProgram, "position"); + mColorLoc = glGetUniformLocation(mProgram, "color"); + + glGenBuffers(1, &mVBO); + glBindBuffer(GL_ARRAY_BUFFER, mVBO); + + static float vertices[] = { + 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, + -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, + }; + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + glEnableVertexAttribArray(position_loc); + glVertexAttribPointer(position_loc, 2, GL_FLOAT, GL_FALSE, 0, 0); + + ASSERT_GL_NO_ERROR(); + } + + void TearDown() override + { + glDeleteBuffers(1, &mVBO); + glDeleteProgram(mProgram); + + ASSERT_GL_NO_ERROR(); + + ANGLETest::TearDown(); + } + + void prepareForDraw(SetupFBOType fbo_type) + { + glActiveTexture(GL_TEXTURE0); + glGenTextures(1, &mTexture); + glBindTexture(GL_TEXTURE_2D, mTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, + NULL); + glBindTexture(GL_TEXTURE_2D, 0); + + glGenRenderbuffers(1, &mStencilRB); + glBindRenderbuffer(GL_RENDERBUFFER, mStencilRB); + + if (fbo_type == MixedSampleFBO) + { + // Create a sample buffer. + GLsizei num_samples = 8, max_samples = 0; + glGetIntegerv(GL_MAX_SAMPLES, &max_samples); + num_samples = std::min(num_samples, max_samples); + glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, num_samples, GL_STENCIL_INDEX8, + kWidth, kHeight); + GLint param = 0; + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, ¶m); + EXPECT_GT(param, 1); + } + else + { + glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, kWidth, kHeight); + } + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + glGenFramebuffers(1, &mSampleFBO); + glBindFramebuffer(GL_FRAMEBUFFER, mSampleFBO); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, + mStencilRB); + EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), + glCheckFramebufferStatus(GL_FRAMEBUFFER)); + + glUseProgram(mProgram); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glViewport(0, 0, kWidth, kHeight); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClearStencil(1); + glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + glEnable(GL_STENCIL_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glStencilMask(0xffffffff); + glStencilFunc(GL_EQUAL, 1, 0xffffffff); + glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); + + ASSERT_GL_NO_ERROR(); + } + + void cleanup() + { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &mSampleFBO); + glDeleteTextures(1, &mTexture); + glDeleteRenderbuffers(1, &mStencilRB); + + ASSERT_GL_NO_ERROR(); + } + + GLuint mSampleFBO; + GLuint mStencilRB; + GLuint mTexture; + + GLuint mProgram; + GLuint mVBO; + GLint mColorLoc; +}; + +} // + +TEST_P(CHROMIUMFramebufferMixedSamplesTest, StateSettingTest) +{ + if (!isApplicable()) + { + return; + } + + GLint value = -1; + glGetIntegerv(GL_COVERAGE_MODULATION_CHROMIUM, &value); + EXPECT_EQ(GL_NONE, value); + GLenum kValues[] = {GL_NONE, GL_RGB, GL_RGBA, GL_ALPHA}; + for (auto expect : kValues) + { + glCoverageModulationCHROMIUM(expect); + value = -1; + glGetIntegerv(GL_COVERAGE_MODULATION_CHROMIUM, &value); + EXPECT_EQ(expect, static_cast<GLenum>(value)); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + } + + glCoverageModulationCHROMIUM(GL_BYTE); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), glGetError()); + value = -1; + glGetIntegerv(GL_COVERAGE_MODULATION_CHROMIUM, &value); + EXPECT_EQ(static_cast<GLenum>(GL_ALPHA), static_cast<GLenum>(value)); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); +} + +// The test pattern is as follows: +// A green triangle (bottom left, top right, top left). +// A blue triangle (top left, bottom right, bottom left). +// The triangles will overlap but overlap only contains green pixels, +// due to each draw erasing its area from stencil. +// The blue triangle will fill only the area (bottom left, center, +// bottom right). + +// The test tests that CoverageModulation call works. +// The fractional pixels of both triangles end up being modulated +// by the coverage of the fragment. Test that drawing with and without +// CoverageModulation causes the result to be different. +TEST_P(CHROMIUMFramebufferMixedSamplesTest, CoverageModulation) +{ + if (!isApplicable()) + { + return; + } + static const float kBlue[] = {0.0f, 0.0f, 1.0f, 1.0f}; + static const float kGreen[] = {0.0f, 1.0f, 0.0f, 1.0f}; + std::unique_ptr<uint8_t[]> results[3]; + const GLint kResultSize = kWidth * kHeight * 4; + + for (int pass = 0; pass < 3; ++pass) + { + prepareForDraw(MixedSampleFBO); + if (pass == 1) + { + glCoverageModulationCHROMIUM(GL_RGBA); + } + glUniform4fv(mColorLoc, 1, kGreen); + glDrawArrays(GL_TRIANGLES, 0, 3); + + glUniform4fv(mColorLoc, 1, kBlue); + glDrawArrays(GL_TRIANGLES, 3, 3); + if (pass == 1) + { + glCoverageModulationCHROMIUM(GL_NONE); + } + results[pass].reset(new uint8_t[kResultSize]); + memset(results[pass].get(), 123u, kResultSize); + glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, results[pass].get()); + + cleanup(); + } + + EXPECT_NE(0, memcmp(results[0].get(), results[1].get(), kResultSize)); + // Verify that rendering is deterministic, so that the pass above does not + // come from non-deterministic rendering. + EXPECT_EQ(0, memcmp(results[0].get(), results[2].get(), kResultSize)); +} + +// The test tests that the stencil buffer can be multisampled, even though the +// color buffer is single-sampled. Draws the same pattern with single-sample +// stencil buffer and with multisample stencil buffer. The images should differ. +TEST_P(CHROMIUMFramebufferMixedSamplesTest, MultisampleStencilEffective) +{ + if (!isApplicable()) + { + return; + } + + static const float kBlue[] = {0.0f, 0.0f, 1.0f, 1.0f}; + static const float kGreen[] = {0.0f, 1.0f, 0.0f, 1.0f}; + + std::unique_ptr<uint8_t[]> results[3]; + const GLint kResultSize = kWidth * kHeight * 4; + + for (int pass = 0; pass < 3; ++pass) + { + if (pass == 1) + { + prepareForDraw(MixedSampleFBO); + } + else + { + prepareForDraw(SingleSampleFBO); + } + glUniform4fv(mColorLoc, 1, kGreen); + glDrawArrays(GL_TRIANGLES, 0, 3); + + glUniform4fv(mColorLoc, 1, kBlue); + glDrawArrays(GL_TRIANGLES, 3, 3); + + results[pass].reset(new uint8_t[kResultSize]); + memset(results[pass].get(), 12u, kResultSize); + glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, results[pass].get()); + + cleanup(); + } + + EXPECT_NE(0, memcmp(results[0].get(), results[1].get(), kResultSize)); + // Verify that rendering is deterministic, so that the pass above does not + // come from non-deterministic rendering. + EXPECT_EQ(0, memcmp(results[0].get(), results[2].get(), kResultSize)); +} + +ANGLE_INSTANTIATE_TEST(CHROMIUMFramebufferMixedSamplesTest, + ES2_OPENGL(), + ES2_OPENGLES(), + ES3_OPENGL()); |