summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/tests/gl_tests/FramebufferMixedSamplesTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/src/tests/gl_tests/FramebufferMixedSamplesTest.cpp')
-rwxr-xr-xgfx/angle/src/tests/gl_tests/FramebufferMixedSamplesTest.cpp291
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, &param);
+ 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());