1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // CHROMIUMFramebufferMixedSamplesTest
7 // Test CHROMIUM subset of NV_framebuffer_mixed_samples.
8 // This extension allows rendering to a framebuffer that has different
9 // sample counts for different render buffers (stencil, depth, color)
10
11 #include "test_utils/ANGLETest.h"
12
13 using namespace angle;
14
15 namespace
16 {
17
18 const GLuint kWidth = 100;
19 const GLuint kHeight = 100;
20
21 class CHROMIUMFramebufferMixedSamplesTest : public ANGLETest<>
22 {
23 protected:
24 enum SetupFBOType
25 {
26 MixedSampleFBO, // 1 color sample, N stencil samples.
27 SingleSampleFBO, // 1 color sample, 1 stencil sample.
28 };
29
isApplicable() const30 bool isApplicable() const
31 {
32 return IsGLExtensionEnabled("GL_CHROMIUM_framebuffer_mixed_samples") &&
33 IsGLExtensionEnabled("GL_OES_rgb8_rgba8");
34 }
35
testSetUp()36 void testSetUp() override
37 {
38 mProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
39
40 GLuint position_loc = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
41 mColorLoc = glGetUniformLocation(mProgram, essl1_shaders::ColorUniform());
42
43 glGenBuffers(1, &mVBO);
44 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
45
46 static float vertices[] = {
47 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
48 -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
49 };
50 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
51 glEnableVertexAttribArray(position_loc);
52 glVertexAttribPointer(position_loc, 2, GL_FLOAT, GL_FALSE, 0, 0);
53
54 ASSERT_GL_NO_ERROR();
55 }
56
testTearDown()57 void testTearDown() override
58 {
59 glDeleteBuffers(1, &mVBO);
60 glDeleteProgram(mProgram);
61
62 ASSERT_GL_NO_ERROR();
63 }
64
prepareForDraw(SetupFBOType fbo_type)65 void prepareForDraw(SetupFBOType fbo_type)
66 {
67 glActiveTexture(GL_TEXTURE0);
68 glGenTextures(1, &mTexture);
69 glBindTexture(GL_TEXTURE_2D, mTexture);
70 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
71 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
72 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
73 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
74 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
75 nullptr);
76 glBindTexture(GL_TEXTURE_2D, 0);
77
78 glGenRenderbuffers(1, &mStencilRB);
79 glBindRenderbuffer(GL_RENDERBUFFER, mStencilRB);
80
81 if (fbo_type == MixedSampleFBO)
82 {
83 // Create a sample buffer.
84 GLsizei num_samples = 8, max_samples = 0;
85 glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
86 num_samples = std::min(num_samples, max_samples);
87 glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, num_samples, GL_STENCIL_INDEX8,
88 kWidth, kHeight);
89 GLint param = 0;
90 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, ¶m);
91 EXPECT_GT(param, 1);
92 }
93 else
94 {
95 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, kWidth, kHeight);
96 }
97 glBindRenderbuffer(GL_RENDERBUFFER, 0);
98
99 glGenFramebuffers(1, &mSampleFBO);
100 glBindFramebuffer(GL_FRAMEBUFFER, mSampleFBO);
101 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
102 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
103 mStencilRB);
104 EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
105 glCheckFramebufferStatus(GL_FRAMEBUFFER));
106
107 glUseProgram(mProgram);
108 glBindBuffer(GL_ARRAY_BUFFER, 0);
109 glViewport(0, 0, kWidth, kHeight);
110 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
111 glClearStencil(1);
112 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
113 glEnable(GL_STENCIL_TEST);
114 glEnable(GL_BLEND);
115 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
116 glStencilMask(0xffffffff);
117 glStencilFunc(GL_EQUAL, 1, 0xffffffff);
118 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
119
120 ASSERT_GL_NO_ERROR();
121 }
122
cleanup()123 void cleanup()
124 {
125 glBindFramebuffer(GL_FRAMEBUFFER, 0);
126 glDeleteFramebuffers(1, &mSampleFBO);
127 glDeleteTextures(1, &mTexture);
128 glDeleteRenderbuffers(1, &mStencilRB);
129
130 ASSERT_GL_NO_ERROR();
131 }
132
133 GLuint mSampleFBO;
134 GLuint mStencilRB;
135 GLuint mTexture;
136
137 GLuint mProgram;
138 GLuint mVBO;
139 GLint mColorLoc;
140 };
141
142 } // namespace
143
TEST_P(CHROMIUMFramebufferMixedSamplesTest,StateSettingTest)144 TEST_P(CHROMIUMFramebufferMixedSamplesTest, StateSettingTest)
145 {
146 if (!isApplicable())
147 {
148 return;
149 }
150
151 GLint value = -1;
152 glGetIntegerv(GL_COVERAGE_MODULATION_CHROMIUM, &value);
153 EXPECT_EQ(GL_NONE, value);
154 GLenum kValues[] = {GL_NONE, GL_RGB, GL_RGBA, GL_ALPHA};
155 for (auto expect : kValues)
156 {
157 glCoverageModulationCHROMIUM(expect);
158 value = -1;
159 glGetIntegerv(GL_COVERAGE_MODULATION_CHROMIUM, &value);
160 EXPECT_EQ(expect, static_cast<GLenum>(value));
161 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
162 }
163
164 glCoverageModulationCHROMIUM(GL_BYTE);
165 EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), glGetError());
166 value = -1;
167 glGetIntegerv(GL_COVERAGE_MODULATION_CHROMIUM, &value);
168 EXPECT_EQ(static_cast<GLenum>(GL_ALPHA), static_cast<GLenum>(value));
169 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
170 }
171
172 // The test pattern is as follows:
173 // A green triangle (bottom left, top right, top left).
174 // A blue triangle (top left, bottom right, bottom left).
175 // The triangles will overlap but overlap only contains green pixels,
176 // due to each draw erasing its area from stencil.
177 // The blue triangle will fill only the area (bottom left, center,
178 // bottom right).
179
180 // The test tests that CoverageModulation call works.
181 // The fractional pixels of both triangles end up being modulated
182 // by the coverage of the fragment. Test that drawing with and without
183 // CoverageModulation causes the result to be different.
TEST_P(CHROMIUMFramebufferMixedSamplesTest,CoverageModulation)184 TEST_P(CHROMIUMFramebufferMixedSamplesTest, CoverageModulation)
185 {
186 if (!isApplicable())
187 {
188 return;
189 }
190 static const float kBlue[] = {0.0f, 0.0f, 1.0f, 1.0f};
191 static const float kGreen[] = {0.0f, 1.0f, 0.0f, 1.0f};
192 std::unique_ptr<uint8_t[]> results[3];
193 const GLint kResultSize = kWidth * kHeight * 4;
194
195 for (int pass = 0; pass < 3; ++pass)
196 {
197 prepareForDraw(MixedSampleFBO);
198 if (pass == 1)
199 {
200 glCoverageModulationCHROMIUM(GL_RGBA);
201 }
202 glUniform4fv(mColorLoc, 1, kGreen);
203 glDrawArrays(GL_TRIANGLES, 0, 3);
204
205 glUniform4fv(mColorLoc, 1, kBlue);
206 glDrawArrays(GL_TRIANGLES, 3, 3);
207 if (pass == 1)
208 {
209 glCoverageModulationCHROMIUM(GL_NONE);
210 }
211 results[pass].reset(new uint8_t[kResultSize]);
212 memset(results[pass].get(), 123u, kResultSize);
213 glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, results[pass].get());
214
215 cleanup();
216 }
217
218 EXPECT_NE(0, memcmp(results[0].get(), results[1].get(), kResultSize));
219 // Verify that rendering is deterministic, so that the pass above does not
220 // come from non-deterministic rendering.
221 EXPECT_EQ(0, memcmp(results[0].get(), results[2].get(), kResultSize));
222 }
223
224 // The test tests that the stencil buffer can be multisampled, even though the
225 // color buffer is single-sampled. Draws the same pattern with single-sample
226 // stencil buffer and with multisample stencil buffer. The images should differ.
TEST_P(CHROMIUMFramebufferMixedSamplesTest,MultisampleStencilEffective)227 TEST_P(CHROMIUMFramebufferMixedSamplesTest, MultisampleStencilEffective)
228 {
229 if (!isApplicable())
230 {
231 return;
232 }
233
234 static const float kBlue[] = {0.0f, 0.0f, 1.0f, 1.0f};
235 static const float kGreen[] = {0.0f, 1.0f, 0.0f, 1.0f};
236
237 std::unique_ptr<uint8_t[]> results[3];
238 const GLint kResultSize = kWidth * kHeight * 4;
239
240 for (int pass = 0; pass < 3; ++pass)
241 {
242 if (pass == 1)
243 {
244 prepareForDraw(MixedSampleFBO);
245 }
246 else
247 {
248 prepareForDraw(SingleSampleFBO);
249 }
250 glUniform4fv(mColorLoc, 1, kGreen);
251 glDrawArrays(GL_TRIANGLES, 0, 3);
252
253 glUniform4fv(mColorLoc, 1, kBlue);
254 glDrawArrays(GL_TRIANGLES, 3, 3);
255
256 results[pass].reset(new uint8_t[kResultSize]);
257 memset(results[pass].get(), 12u, kResultSize);
258 glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, results[pass].get());
259
260 cleanup();
261 }
262
263 EXPECT_NE(0, memcmp(results[0].get(), results[1].get(), kResultSize));
264 // Verify that rendering is deterministic, so that the pass above does not
265 // come from non-deterministic rendering.
266 EXPECT_EQ(0, memcmp(results[0].get(), results[2].get(), kResultSize));
267 }
268
269 ANGLE_INSTANTIATE_TEST_ES2(CHROMIUMFramebufferMixedSamplesTest);
270